mirror of
https://forge.chapril.org/tykayn/orgmode-to-gemini-blog
synced 2025-11-19 23:00:35 +01:00
930 lines
35 KiB
Python
930 lines
35 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
# -*- coding: utf-8 -*-
|
||
|
|
"""
|
||
|
|
Script pour générer des statistiques détaillées sur les blogs
|
||
|
|
et créer des pages HTML avec graphiques pour chaque blog.
|
||
|
|
"""
|
||
|
|
|
||
|
|
import os
|
||
|
|
import re
|
||
|
|
import argparse
|
||
|
|
import shutil
|
||
|
|
from datetime import datetime
|
||
|
|
from collections import defaultdict
|
||
|
|
import locale
|
||
|
|
|
||
|
|
try:
|
||
|
|
import matplotlib
|
||
|
|
matplotlib.use('Agg') # Backend non-interactif
|
||
|
|
import matplotlib.pyplot as plt
|
||
|
|
import matplotlib.dates as mdates
|
||
|
|
HAS_MATPLOTLIB = True
|
||
|
|
except ImportError:
|
||
|
|
HAS_MATPLOTLIB = False
|
||
|
|
print("Attention: matplotlib n'est pas installé. Les graphiques ne seront pas générés.")
|
||
|
|
|
||
|
|
from jinja2 import Environment, FileSystemLoader
|
||
|
|
|
||
|
|
# Importer les fonctions utilitaires
|
||
|
|
from utils.utils import (
|
||
|
|
find_year_and_slug_on_filename,
|
||
|
|
get_blog_template_conf,
|
||
|
|
find_extract_in_content_org,
|
||
|
|
format_date_str
|
||
|
|
)
|
||
|
|
|
||
|
|
# Vitesse de lecture en mots par minute
|
||
|
|
LECTURE_MOTS_PAR_MINUTE = 220
|
||
|
|
|
||
|
|
|
||
|
|
def extraire_date_du_contenu(content):
|
||
|
|
"""
|
||
|
|
Extrait la date de publication depuis les métadonnées du fichier org.
|
||
|
|
Recherche #+CREATED ou #+post_date_published
|
||
|
|
"""
|
||
|
|
# Chercher #+CREATED
|
||
|
|
match = re.search(r'#\+CREATED:\s*(.+)', content)
|
||
|
|
if match:
|
||
|
|
date_str = match.group(1).strip()
|
||
|
|
# Formats possibles: YYYY-MM-DD HH:MM:SS, YYYY-MM-DD
|
||
|
|
try:
|
||
|
|
return datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S')
|
||
|
|
except ValueError:
|
||
|
|
try:
|
||
|
|
return datetime.strptime(date_str, '%Y-%m-%d')
|
||
|
|
except ValueError:
|
||
|
|
pass
|
||
|
|
|
||
|
|
# Chercher #+post_date_published
|
||
|
|
match = re.search(r'#\+post_date_published:\s*<(.+)>', content)
|
||
|
|
if match:
|
||
|
|
date_str = match.group(1).strip()
|
||
|
|
try:
|
||
|
|
return datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S')
|
||
|
|
except ValueError:
|
||
|
|
try:
|
||
|
|
return datetime.strptime(date_str, '%Y-%m-%d')
|
||
|
|
except ValueError:
|
||
|
|
pass
|
||
|
|
|
||
|
|
return None
|
||
|
|
|
||
|
|
|
||
|
|
def extraire_date_du_fichier(filename):
|
||
|
|
"""
|
||
|
|
Extrait la date du nom de fichier en utilisant find_year_and_slug_on_filename de utils.py.
|
||
|
|
"""
|
||
|
|
date_str, annee, slug = find_year_and_slug_on_filename(filename)
|
||
|
|
if not date_str:
|
||
|
|
return None
|
||
|
|
|
||
|
|
try:
|
||
|
|
# Format YYYYMMDDHHMMSS (14 caractères)
|
||
|
|
if len(date_str) == 14:
|
||
|
|
if 'T' not in date_str:
|
||
|
|
return datetime.strptime(date_str, '%Y%m%d%H%M%S')
|
||
|
|
else:
|
||
|
|
# Format YYYYMMDDTHHMMSS ou YYYYMMDDTHHMM
|
||
|
|
if len(date_str) == 15:
|
||
|
|
return datetime.strptime(date_str, '%Y%m%dT%H%M%S')
|
||
|
|
elif len(date_str) >= 13:
|
||
|
|
base_date = date_str[:12]
|
||
|
|
return datetime.strptime(base_date, '%Y%m%dT%H%M')
|
||
|
|
# Format YYYYMMDD (8 caractères)
|
||
|
|
elif len(date_str) >= 8:
|
||
|
|
return datetime.strptime(date_str[:8], '%Y%m%d')
|
||
|
|
except ValueError:
|
||
|
|
pass
|
||
|
|
|
||
|
|
return None
|
||
|
|
|
||
|
|
|
||
|
|
def compter_mots(contenu):
|
||
|
|
"""Compte le nombre de mots dans le contenu (sans les métadonnées)."""
|
||
|
|
# Utiliser find_extract_in_content_org pour nettoyer le contenu
|
||
|
|
contenu_clean = find_extract_in_content_org(contenu)
|
||
|
|
|
||
|
|
# Supprimer les liens org-mode pour ne compter que le texte
|
||
|
|
contenu_clean = re.sub(r'\[\[([^\]]+)\]\[([^\]]+)\]\]', r'\2', contenu_clean)
|
||
|
|
contenu_clean = re.sub(r'\[\[([^\]]+)\]\]', r'\1', contenu_clean)
|
||
|
|
|
||
|
|
# Compter les mots
|
||
|
|
mots = contenu_clean.split()
|
||
|
|
return len([m for m in mots if len(m.strip()) > 0])
|
||
|
|
|
||
|
|
|
||
|
|
def compter_signes(contenu):
|
||
|
|
"""Compte le nombre de signes espaces compris dans le contenu."""
|
||
|
|
# Utiliser find_extract_in_content_org pour nettoyer le contenu
|
||
|
|
contenu_clean = find_extract_in_content_org(contenu)
|
||
|
|
return len(contenu_clean)
|
||
|
|
|
||
|
|
|
||
|
|
def compter_liens(contenu):
|
||
|
|
"""
|
||
|
|
Compte le nombre de liens dans le contenu (format [[url]] ou [[url][texte]]).
|
||
|
|
Distingue les liens vers des images des autres liens.
|
||
|
|
Retourne un tuple (nb_liens_images, nb_liens_autres)
|
||
|
|
"""
|
||
|
|
# Compter les liens org-mode
|
||
|
|
liens = re.findall(r'\[\[([^\]]+)\](\[[^\]]+\])?\]', contenu)
|
||
|
|
|
||
|
|
nb_images = 0
|
||
|
|
nb_autres = 0
|
||
|
|
|
||
|
|
# Extensions d'images courantes
|
||
|
|
extensions_images = ['.jpg', '.jpeg', '.png', '.gif', '.svg', '.webp', '.bmp', '.ico']
|
||
|
|
|
||
|
|
for lien_match in liens:
|
||
|
|
url = lien_match[0]
|
||
|
|
# Vérifier si c'est une image
|
||
|
|
is_image = any(url.lower().endswith(ext) for ext in extensions_images) or \
|
||
|
|
'/image' in url.lower() or \
|
||
|
|
'img' in url.lower()
|
||
|
|
|
||
|
|
if is_image:
|
||
|
|
nb_images += 1
|
||
|
|
else:
|
||
|
|
nb_autres += 1
|
||
|
|
|
||
|
|
return nb_images, nb_autres
|
||
|
|
|
||
|
|
|
||
|
|
def analyser_article(filepath):
|
||
|
|
"""
|
||
|
|
Analyse un fichier article et retourne ses statistiques.
|
||
|
|
"""
|
||
|
|
try:
|
||
|
|
with open(filepath, 'r', encoding='utf-8') as f:
|
||
|
|
contenu = f.read()
|
||
|
|
|
||
|
|
# Extraire la date
|
||
|
|
date_pub = extraire_date_du_contenu(contenu)
|
||
|
|
if not date_pub:
|
||
|
|
date_pub = extraire_date_du_fichier(os.path.basename(filepath))
|
||
|
|
if not date_pub:
|
||
|
|
# Utiliser la date de modification du fichier en dernier recours
|
||
|
|
date_pub = datetime.fromtimestamp(os.path.getmtime(filepath))
|
||
|
|
|
||
|
|
# Calculer les statistiques
|
||
|
|
nb_mots = compter_mots(contenu)
|
||
|
|
nb_signes = compter_signes(contenu)
|
||
|
|
nb_liens_images, nb_liens_autres = compter_liens(contenu)
|
||
|
|
|
||
|
|
# Temps de lecture (en minutes)
|
||
|
|
temps_lecture = nb_mots / LECTURE_MOTS_PAR_MINUTE if nb_mots > 0 else 0
|
||
|
|
|
||
|
|
return {
|
||
|
|
'date': date_pub,
|
||
|
|
'fichier': os.path.basename(filepath),
|
||
|
|
'mots': nb_mots,
|
||
|
|
'signes': nb_signes,
|
||
|
|
'liens_images': nb_liens_images,
|
||
|
|
'liens_autres': nb_liens_autres,
|
||
|
|
'liens': nb_liens_images + nb_liens_autres, # Total pour compatibilité
|
||
|
|
'temps_lecture': temps_lecture
|
||
|
|
}
|
||
|
|
except Exception as e:
|
||
|
|
print(f"Erreur lors de l'analyse de {filepath}: {e}")
|
||
|
|
return None
|
||
|
|
|
||
|
|
|
||
|
|
def analyser_blog(blog_path):
|
||
|
|
"""
|
||
|
|
Analyse tous les articles d'un blog et retourne les statistiques.
|
||
|
|
"""
|
||
|
|
articles = []
|
||
|
|
|
||
|
|
# Chercher dans lang_fr et lang_en
|
||
|
|
for lang_dir in ['lang_fr', 'lang_en']:
|
||
|
|
lang_path = os.path.join(blog_path, lang_dir)
|
||
|
|
if not os.path.exists(lang_path):
|
||
|
|
continue
|
||
|
|
|
||
|
|
# Lister tous les fichiers .org
|
||
|
|
for filename in os.listdir(lang_path):
|
||
|
|
if filename.endswith('.org'):
|
||
|
|
filepath = os.path.join(lang_path, filename)
|
||
|
|
stats = analyser_article(filepath)
|
||
|
|
if stats:
|
||
|
|
articles.append(stats)
|
||
|
|
|
||
|
|
return articles
|
||
|
|
|
||
|
|
|
||
|
|
def calculer_statistiques_par_mois(articles):
|
||
|
|
"""
|
||
|
|
Calcule les statistiques agrégées par mois.
|
||
|
|
"""
|
||
|
|
stats_par_mois = defaultdict(lambda: {
|
||
|
|
'articles': [],
|
||
|
|
'mots_total': 0,
|
||
|
|
'signes_total': 0,
|
||
|
|
'liens_total': 0,
|
||
|
|
'liens_images_total': 0,
|
||
|
|
'liens_autres_total': 0,
|
||
|
|
'temps_lecture_total': 0
|
||
|
|
})
|
||
|
|
|
||
|
|
for article in articles:
|
||
|
|
mois_cle = article['date'].strftime('%Y-%m')
|
||
|
|
stats_par_mois[mois_cle]['articles'].append(article)
|
||
|
|
stats_par_mois[mois_cle]['mots_total'] += article['mots']
|
||
|
|
stats_par_mois[mois_cle]['signes_total'] += article['signes']
|
||
|
|
stats_par_mois[mois_cle]['liens_total'] += article['liens']
|
||
|
|
stats_par_mois[mois_cle]['liens_images_total'] += article['liens_images']
|
||
|
|
stats_par_mois[mois_cle]['liens_autres_total'] += article['liens_autres']
|
||
|
|
stats_par_mois[mois_cle]['temps_lecture_total'] += article['temps_lecture']
|
||
|
|
|
||
|
|
# Formater les mois pour le template
|
||
|
|
stats_formatees = {}
|
||
|
|
try:
|
||
|
|
locale.setlocale(locale.LC_TIME, 'fr_FR.UTF-8')
|
||
|
|
except:
|
||
|
|
try:
|
||
|
|
locale.setlocale(locale.LC_TIME, 'fra')
|
||
|
|
except:
|
||
|
|
pass
|
||
|
|
|
||
|
|
for mois_cle, stats in sorted(stats_par_mois.items()):
|
||
|
|
mois_date = datetime.strptime(mois_cle, '%Y-%m')
|
||
|
|
stats_formatees[mois_cle] = {
|
||
|
|
**stats,
|
||
|
|
'nb_articles': len(stats['articles']),
|
||
|
|
'mois_formate': mois_date.strftime('%B %Y'),
|
||
|
|
'date_debut': mois_date
|
||
|
|
}
|
||
|
|
|
||
|
|
return stats_formatees
|
||
|
|
|
||
|
|
|
||
|
|
def calculer_nanowrimo_mois(mois_cle, stats_mois, aujourdhui, objectif_quotidien=None, objectif_mensuel=None):
|
||
|
|
"""
|
||
|
|
Calcule les statistiques NaNoWriMo pour un mois donné.
|
||
|
|
Objectif par défaut : 1667 signes (espaces compris) par jour.
|
||
|
|
Si objectif_quotidien est fourni, il prend le pas sur le défaut.
|
||
|
|
Si objectif_mensuel est fourni, il prend le pas sur tous les autres.
|
||
|
|
"""
|
||
|
|
import calendar
|
||
|
|
|
||
|
|
mois_date = datetime.strptime(mois_cle, '%Y-%m')
|
||
|
|
annee, mois = mois_date.year, mois_date.month
|
||
|
|
|
||
|
|
# Nombre de jours dans le mois
|
||
|
|
jours_dans_mois = calendar.monthrange(annee, mois)[1]
|
||
|
|
|
||
|
|
# Nombre de jours écoulés dans le mois
|
||
|
|
if mois == aujourdhui.month and annee == aujourdhui.year:
|
||
|
|
jour_actuel = aujourdhui.day
|
||
|
|
elif mois_date > aujourdhui:
|
||
|
|
# Mois futur
|
||
|
|
jour_actuel = 0
|
||
|
|
else:
|
||
|
|
# Mois passé
|
||
|
|
jour_actuel = jours_dans_mois
|
||
|
|
|
||
|
|
# Déterminer l'objectif quotidien
|
||
|
|
if objectif_mensuel is not None:
|
||
|
|
# Objectif mensuel fourni : le diviser par le nombre de jours
|
||
|
|
objectif_quotidien_utilise = objectif_mensuel / jours_dans_mois
|
||
|
|
objectif_total = objectif_mensuel
|
||
|
|
elif objectif_quotidien is not None:
|
||
|
|
# Objectif quotidien fourni
|
||
|
|
objectif_quotidien_utilise = objectif_quotidien
|
||
|
|
objectif_total = objectif_quotidien * jours_dans_mois
|
||
|
|
else:
|
||
|
|
# Objectif par défaut NaNoWriMo
|
||
|
|
objectif_quotidien_utilise = 1667
|
||
|
|
objectif_total = 1667 * jours_dans_mois
|
||
|
|
|
||
|
|
# Objectif jusqu'à aujourd'hui (pour le mois courant)
|
||
|
|
objectif_jusqu_aujourdhui = objectif_quotidien_utilise * jour_actuel if jour_actuel > 0 else 0
|
||
|
|
|
||
|
|
# Signes réalisés
|
||
|
|
signes_realises = stats_mois.get('signes_total', 0)
|
||
|
|
|
||
|
|
# Calculer les signes par jour pour ce mois
|
||
|
|
signes_par_jour = {}
|
||
|
|
for article in stats_mois.get('articles', []):
|
||
|
|
jour = article['date'].day
|
||
|
|
if jour not in signes_par_jour:
|
||
|
|
signes_par_jour[jour] = 0
|
||
|
|
signes_par_jour[jour] += article['signes']
|
||
|
|
|
||
|
|
# Signes aujourd'hui (si on est dans ce mois)
|
||
|
|
signes_aujourdhui = signes_par_jour.get(aujourdhui.day, 0) if \
|
||
|
|
(mois == aujourdhui.month and annee == aujourdhui.year) else 0
|
||
|
|
|
||
|
|
# Calculer le pourcentage
|
||
|
|
if objectif_jusqu_aujourdhui > 0:
|
||
|
|
pourcentage_realise = min(100, (signes_realises / objectif_jusqu_aujourdhui) * 100)
|
||
|
|
else:
|
||
|
|
pourcentage_realise = 0
|
||
|
|
|
||
|
|
# Dépassement
|
||
|
|
depassement = max(0, signes_realises - objectif_total)
|
||
|
|
depassement_pourcentage = (depassement / objectif_total * 100) if objectif_total > 0 else 0
|
||
|
|
|
||
|
|
return {
|
||
|
|
'mois_cle': mois_cle,
|
||
|
|
'mois_formate': mois_date.strftime('%B %Y'),
|
||
|
|
'jours_dans_mois': jours_dans_mois,
|
||
|
|
'jour_actuel': jour_actuel,
|
||
|
|
'objectif_total': objectif_total,
|
||
|
|
'objectif_jusqu_aujourdhui': objectif_jusqu_aujourdhui,
|
||
|
|
'signes_realises': signes_realises,
|
||
|
|
'signes_aujourdhui': signes_aujourdhui,
|
||
|
|
'pourcentage_realise': pourcentage_realise,
|
||
|
|
'depassement': depassement,
|
||
|
|
'depassement_pourcentage': depassement_pourcentage,
|
||
|
|
'est_mois_courant': (mois == aujourdhui.month and annee == aujourdhui.year),
|
||
|
|
'est_mois_futur': mois_date > aujourdhui,
|
||
|
|
'objectif_quotidien': objectif_quotidien_utilise
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def calculer_stats_nanowrimo(stats_par_mois, objectif_articles_mois_courant=None, objectif_quotidien=None, objectif_mensuel=None):
|
||
|
|
"""
|
||
|
|
Calcule les statistiques NaNoWriMo pour les 3 derniers mois.
|
||
|
|
Retourne les mois dans l'ordre chronologique inverse (du plus récent au plus ancien).
|
||
|
|
"""
|
||
|
|
aujourdhui = datetime.now()
|
||
|
|
|
||
|
|
# Obtenir les 3 derniers mois (en incluant le mois courant)
|
||
|
|
# Ordre : mois courant (i=0), mois précédent (i=1), 2 mois avant (i=2)
|
||
|
|
derniers_mois = []
|
||
|
|
for i in range(3):
|
||
|
|
mois_date = aujourdhui.replace(day=1)
|
||
|
|
# Reculer de i mois
|
||
|
|
for _ in range(i):
|
||
|
|
# Mois précédent
|
||
|
|
if mois_date.month == 1:
|
||
|
|
mois_date = mois_date.replace(year=mois_date.year - 1, month=12)
|
||
|
|
else:
|
||
|
|
mois_date = mois_date.replace(month=mois_date.month - 1)
|
||
|
|
|
||
|
|
mois_cle = mois_date.strftime('%Y-%m')
|
||
|
|
# Récupérer les stats du mois, même s'il n'y a pas d'articles
|
||
|
|
stats_mois = stats_par_mois.get(mois_cle, {
|
||
|
|
'articles': [],
|
||
|
|
'signes_total': 0,
|
||
|
|
'nb_articles': 0,
|
||
|
|
'mots_total': 0,
|
||
|
|
'liens_total': 0,
|
||
|
|
'liens_images_total': 0,
|
||
|
|
'liens_autres_total': 0,
|
||
|
|
'temps_lecture_total': 0
|
||
|
|
})
|
||
|
|
|
||
|
|
stats_nanowrimo = calculer_nanowrimo_mois(mois_cle, stats_mois, aujourdhui, objectif_quotidien, objectif_mensuel)
|
||
|
|
|
||
|
|
# Ajouter l'objectif d'articles pour le mois courant
|
||
|
|
if stats_nanowrimo['est_mois_courant'] and objectif_articles_mois_courant is not None:
|
||
|
|
stats_nanowrimo['objectif_articles'] = objectif_articles_mois_courant
|
||
|
|
stats_nanowrimo['articles_realises'] = stats_mois.get('nb_articles', 0)
|
||
|
|
elif stats_nanowrimo['est_mois_courant']:
|
||
|
|
# Si pas d'objectif spécifié, calculer la moyenne mensuelle
|
||
|
|
if len(stats_par_mois) > 0:
|
||
|
|
total_articles = sum(len(stats.get('articles', [])) for stats in stats_par_mois.values())
|
||
|
|
nb_mois = len(stats_par_mois)
|
||
|
|
stats_nanowrimo['objectif_articles'] = int(total_articles / nb_mois) if nb_mois > 0 else 0
|
||
|
|
else:
|
||
|
|
stats_nanowrimo['objectif_articles'] = None
|
||
|
|
stats_nanowrimo['articles_realises'] = stats_mois.get('nb_articles', 0)
|
||
|
|
else:
|
||
|
|
stats_nanowrimo['objectif_articles'] = None
|
||
|
|
stats_nanowrimo['articles_realises'] = stats_mois.get('nb_articles', 0)
|
||
|
|
|
||
|
|
derniers_mois.append(stats_nanowrimo)
|
||
|
|
|
||
|
|
# Inverser pour avoir du plus récent au plus ancien
|
||
|
|
return derniers_mois
|
||
|
|
|
||
|
|
|
||
|
|
def generer_graphiques(blog_name, stats_par_mois, output_dir):
|
||
|
|
"""
|
||
|
|
Génère les graphiques pour un blog.
|
||
|
|
"""
|
||
|
|
if not HAS_MATPLOTLIB:
|
||
|
|
return []
|
||
|
|
|
||
|
|
graphiques = []
|
||
|
|
|
||
|
|
# Préparer les données
|
||
|
|
mois = []
|
||
|
|
nb_articles = []
|
||
|
|
mots_totaux = []
|
||
|
|
signes_totaux = []
|
||
|
|
temps_lecture = []
|
||
|
|
|
||
|
|
for mois_cle, stats in stats_par_mois.items():
|
||
|
|
mois.append(datetime.strptime(mois_cle, '%Y-%m'))
|
||
|
|
nb_articles.append(len(stats['articles']))
|
||
|
|
mots_totaux.append(stats['mots_total'])
|
||
|
|
signes_totaux.append(stats['signes_total'])
|
||
|
|
temps_lecture.append(stats['temps_lecture_total'])
|
||
|
|
|
||
|
|
if not mois:
|
||
|
|
return []
|
||
|
|
|
||
|
|
# Créer le dossier pour les graphiques
|
||
|
|
graph_dir = os.path.join(output_dir, 'stats_graphs')
|
||
|
|
os.makedirs(graph_dir, exist_ok=True)
|
||
|
|
|
||
|
|
# Graphique 1: Articles par mois
|
||
|
|
fig, ax = plt.subplots(figsize=(12, 6))
|
||
|
|
ax.bar(mois, nb_articles, width=20, color='#4CAF50', alpha=0.7)
|
||
|
|
ax.set_xlabel('Mois', fontsize=12)
|
||
|
|
ax.set_ylabel('Nombre d\'articles', fontsize=12)
|
||
|
|
ax.set_title(f'Articles publiés par mois - {blog_name}', fontsize=14, fontweight='bold')
|
||
|
|
ax.grid(True, alpha=0.3, axis='y')
|
||
|
|
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))
|
||
|
|
ax.xaxis.set_major_locator(mdates.MonthLocator(interval=max(1, len(mois)//12)))
|
||
|
|
plt.xticks(rotation=45, ha='right')
|
||
|
|
plt.tight_layout()
|
||
|
|
graph1_path = os.path.join(graph_dir, 'articles_par_mois.png')
|
||
|
|
plt.savefig(graph1_path, dpi=150, bbox_inches='tight')
|
||
|
|
plt.close()
|
||
|
|
graphiques.append(('articles_par_mois.png', 'Articles publiés par mois'))
|
||
|
|
|
||
|
|
# Graphique 2: Mots totaux par mois
|
||
|
|
fig, ax = plt.subplots(figsize=(12, 6))
|
||
|
|
ax.plot(mois, mots_totaux, marker='o', linewidth=2, markersize=6, color='#2196F3')
|
||
|
|
ax.fill_between(mois, mots_totaux, alpha=0.3, color='#2196F3')
|
||
|
|
ax.set_xlabel('Mois', fontsize=12)
|
||
|
|
ax.set_ylabel('Nombre de mots', fontsize=12)
|
||
|
|
ax.set_title(f'Mots totaux par mois - {blog_name}', fontsize=14, fontweight='bold')
|
||
|
|
ax.grid(True, alpha=0.3)
|
||
|
|
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))
|
||
|
|
ax.xaxis.set_major_locator(mdates.MonthLocator(interval=max(1, len(mois)//12)))
|
||
|
|
plt.xticks(rotation=45, ha='right')
|
||
|
|
plt.tight_layout()
|
||
|
|
graph2_path = os.path.join(graph_dir, 'mots_par_mois.png')
|
||
|
|
plt.savefig(graph2_path, dpi=150, bbox_inches='tight')
|
||
|
|
plt.close()
|
||
|
|
graphiques.append(('mots_par_mois.png', 'Mots totaux par mois'))
|
||
|
|
|
||
|
|
# Graphique 3: Temps de lecture par mois
|
||
|
|
fig, ax = plt.subplots(figsize=(12, 6))
|
||
|
|
ax.bar(mois, temps_lecture, width=20, color='#FF9800', alpha=0.7)
|
||
|
|
ax.set_xlabel('Mois', fontsize=12)
|
||
|
|
ax.set_ylabel('Temps de lecture (minutes)', fontsize=12)
|
||
|
|
ax.set_title(f'Temps de lecture par mois - {blog_name}', fontsize=14, fontweight='bold')
|
||
|
|
ax.grid(True, alpha=0.3, axis='y')
|
||
|
|
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))
|
||
|
|
ax.xaxis.set_major_locator(mdates.MonthLocator(interval=max(1, len(mois)//12)))
|
||
|
|
plt.xticks(rotation=45, ha='right')
|
||
|
|
plt.tight_layout()
|
||
|
|
graph3_path = os.path.join(graph_dir, 'temps_lecture_par_mois.png')
|
||
|
|
plt.savefig(graph3_path, dpi=150, bbox_inches='tight')
|
||
|
|
plt.close()
|
||
|
|
graphiques.append(('temps_lecture_par_mois.png', 'Temps de lecture par mois'))
|
||
|
|
|
||
|
|
return graphiques
|
||
|
|
|
||
|
|
|
||
|
|
def formater_duree(minutes):
|
||
|
|
"""Formate une durée en minutes en texte lisible."""
|
||
|
|
if minutes < 60:
|
||
|
|
return f"{int(minutes)} min"
|
||
|
|
heures = int(minutes // 60)
|
||
|
|
mins = int(minutes % 60)
|
||
|
|
if heures >= 24:
|
||
|
|
jours = heures // 24
|
||
|
|
heures = heures % 24
|
||
|
|
if jours > 0 and heures > 0:
|
||
|
|
return f"{jours}j {heures}h {mins}min"
|
||
|
|
elif jours > 0:
|
||
|
|
return f"{jours}j {mins}min"
|
||
|
|
return f"{heures}h {mins}min" if heures > 0 else f"{int(mins)} min"
|
||
|
|
|
||
|
|
|
||
|
|
def format_number(value):
|
||
|
|
"""Formate un nombre avec des séparateurs de milliers."""
|
||
|
|
return f"{value:,}".replace(',', ' ')
|
||
|
|
|
||
|
|
|
||
|
|
def generer_statistiques_blog(blog_name, sources_dir, html_websites_dir, env, template, objectif_articles_mois_courant=None, objectif_quotidien=None, objectif_mensuel=None):
|
||
|
|
"""
|
||
|
|
Génère les statistiques pour un blog individuel.
|
||
|
|
"""
|
||
|
|
blog_path = os.path.join(sources_dir, blog_name)
|
||
|
|
|
||
|
|
# Analyser les articles
|
||
|
|
articles = analyser_blog(blog_path)
|
||
|
|
|
||
|
|
if not articles:
|
||
|
|
print(f" Aucun article trouvé pour {blog_name}")
|
||
|
|
return None
|
||
|
|
|
||
|
|
print(f" {len(articles)} articles trouvés")
|
||
|
|
|
||
|
|
# Calculer les statistiques par mois
|
||
|
|
stats_par_mois = calculer_statistiques_par_mois(articles)
|
||
|
|
|
||
|
|
# Calculer les statistiques NaNoWriMo pour les 3 derniers mois
|
||
|
|
stats_nanowrimo = calculer_stats_nanowrimo(stats_par_mois, objectif_articles_mois_courant, objectif_quotidien, objectif_mensuel)
|
||
|
|
|
||
|
|
# Créer le dossier de sortie
|
||
|
|
output_dir = os.path.join(html_websites_dir, blog_name)
|
||
|
|
os.makedirs(output_dir, exist_ok=True)
|
||
|
|
|
||
|
|
# Copier le fichier CSS
|
||
|
|
css_source = 'templates/styles/stats.css'
|
||
|
|
css_dest = os.path.join(output_dir, 'stats.css')
|
||
|
|
if os.path.exists(css_source):
|
||
|
|
shutil.copy2(css_source, css_dest)
|
||
|
|
|
||
|
|
# Générer les graphiques
|
||
|
|
graphiques = generer_graphiques(blog_name, stats_par_mois, output_dir)
|
||
|
|
|
||
|
|
# Récupérer la config du blog avec get_blog_template_conf
|
||
|
|
blog_config = get_blog_template_conf(blog_name)
|
||
|
|
|
||
|
|
# Calculer les statistiques globales
|
||
|
|
nb_articles_total = len(articles)
|
||
|
|
mots_total = sum(a['mots'] for a in articles)
|
||
|
|
signes_total = sum(a['signes'] for a in articles)
|
||
|
|
liens_total = sum(a['liens'] for a in articles)
|
||
|
|
liens_images_total = sum(a['liens_images'] for a in articles)
|
||
|
|
liens_autres_total = sum(a['liens_autres'] for a in articles)
|
||
|
|
temps_lecture_total = sum(a['temps_lecture'] for a in articles)
|
||
|
|
|
||
|
|
# Moyennes
|
||
|
|
mots_moyen = mots_total / nb_articles_total if nb_articles_total > 0 else 0
|
||
|
|
liens_moyen = liens_total / nb_articles_total if nb_articles_total > 0 else 0
|
||
|
|
liens_images_moyen = liens_images_total / nb_articles_total if nb_articles_total > 0 else 0
|
||
|
|
liens_autres_moyen = liens_autres_total / nb_articles_total if nb_articles_total > 0 else 0
|
||
|
|
signes_moyen = signes_total / nb_articles_total if nb_articles_total > 0 else 0
|
||
|
|
temps_lecture_par_article = temps_lecture_total / nb_articles_total if nb_articles_total > 0 else 0
|
||
|
|
|
||
|
|
# Calculer la fréquence de rédaction
|
||
|
|
if len(articles) > 1:
|
||
|
|
articles_tries = sorted(articles, key=lambda x: x['date'])
|
||
|
|
premiere_date = articles_tries[0]['date']
|
||
|
|
derniere_date = articles_tries[-1]['date']
|
||
|
|
diff_jours = (derniere_date - premiere_date).days
|
||
|
|
frequence = nb_articles_total / diff_jours * 30 if diff_jours > 0 else 0 # articles par mois
|
||
|
|
else:
|
||
|
|
frequence = 0
|
||
|
|
premiere_date = articles[0]['date'] if articles else None
|
||
|
|
derniere_date = articles[0]['date'] if articles else None
|
||
|
|
|
||
|
|
# Calculer la vitesse d'écriture (mots par mois)
|
||
|
|
if len(stats_par_mois) > 0:
|
||
|
|
mots_par_mois_moyen = sum(stats['mots_total'] for stats in stats_par_mois.values()) / len(stats_par_mois)
|
||
|
|
else:
|
||
|
|
mots_par_mois_moyen = 0
|
||
|
|
|
||
|
|
# Préparer les données pour le template
|
||
|
|
premiere_date_str = premiere_date.strftime('%d/%m/%Y') if premiere_date else 'N/A'
|
||
|
|
derniere_date_str = derniere_date.strftime('%d/%m/%Y') if derniere_date else 'N/A'
|
||
|
|
date_gen = datetime.now().strftime('%d/%m/%Y à %H:%M:%S')
|
||
|
|
|
||
|
|
# Générer le HTML avec le template
|
||
|
|
html_content = template.render(
|
||
|
|
blog_title=blog_config.get('BLOG_TITLE', blog_name),
|
||
|
|
author=blog_config.get('AUTHOR', ''),
|
||
|
|
nb_articles_total=nb_articles_total,
|
||
|
|
mots_total=mots_total,
|
||
|
|
signes_total=signes_total,
|
||
|
|
liens_total=liens_total,
|
||
|
|
liens_images_total=liens_images_total,
|
||
|
|
liens_autres_total=liens_autres_total,
|
||
|
|
temps_lecture_total=temps_lecture_total,
|
||
|
|
mots_moyen=mots_moyen,
|
||
|
|
liens_moyen=liens_moyen,
|
||
|
|
liens_images_moyen=liens_images_moyen,
|
||
|
|
liens_autres_moyen=liens_autres_moyen,
|
||
|
|
signes_moyen=signes_moyen,
|
||
|
|
temps_lecture_par_article=temps_lecture_par_article,
|
||
|
|
frequence=frequence,
|
||
|
|
mots_par_mois_moyen=mots_par_mois_moyen,
|
||
|
|
premiere_date_str=premiere_date_str,
|
||
|
|
derniere_date_str=derniere_date_str,
|
||
|
|
stats_par_mois=stats_par_mois,
|
||
|
|
stats_nanowrimo=stats_nanowrimo,
|
||
|
|
graphiques=graphiques,
|
||
|
|
date_gen=date_gen,
|
||
|
|
lecture_mots_par_minute=LECTURE_MOTS_PAR_MINUTE,
|
||
|
|
css_path='stats.css'
|
||
|
|
)
|
||
|
|
|
||
|
|
# Sauvegarder le HTML
|
||
|
|
html_path = os.path.join(output_dir, 'stats.html')
|
||
|
|
with open(html_path, 'w', encoding='utf-8') as f:
|
||
|
|
f.write(html_content)
|
||
|
|
|
||
|
|
print(f" ✓ Statistiques générées pour {blog_name}")
|
||
|
|
|
||
|
|
# Retourner les données pour une éventuelle combinaison
|
||
|
|
return {
|
||
|
|
'blog_name': blog_name,
|
||
|
|
'blog_title': blog_config.get('BLOG_TITLE', blog_name),
|
||
|
|
'author': blog_config.get('AUTHOR', ''),
|
||
|
|
'articles': articles,
|
||
|
|
'stats_par_mois': stats_par_mois,
|
||
|
|
'graphiques': graphiques,
|
||
|
|
'graph_path': f'{blog_name}/stats_graphs',
|
||
|
|
'nb_articles_total': nb_articles_total,
|
||
|
|
'mots_total': mots_total,
|
||
|
|
'signes_total': signes_total,
|
||
|
|
'liens_total': liens_total,
|
||
|
|
'liens_images_total': liens_images_total,
|
||
|
|
'liens_autres_total': liens_autres_total,
|
||
|
|
'stats_nanowrimo': stats_nanowrimo,
|
||
|
|
'temps_lecture_total': temps_lecture_total,
|
||
|
|
'mots_moyen': mots_moyen,
|
||
|
|
'liens_moyen': liens_moyen,
|
||
|
|
'signes_moyen': signes_moyen,
|
||
|
|
'temps_lecture_par_article': temps_lecture_par_article,
|
||
|
|
'frequence': frequence,
|
||
|
|
'mots_par_mois_moyen': mots_par_mois_moyen,
|
||
|
|
'premiere_date_str': premiere_date_str,
|
||
|
|
'derniere_date_str': derniere_date_str
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def calculer_nanowrimo_combine(blogs_data, objectif_quotidien=None, objectif_mensuel=None):
|
||
|
|
"""
|
||
|
|
Calcule les statistiques NaNoWriMo combinées pour tous les blogs sur les 3 derniers mois.
|
||
|
|
Additionne les signes de tous les blogs pour chaque mois.
|
||
|
|
"""
|
||
|
|
aujourdhui = datetime.now()
|
||
|
|
|
||
|
|
# Combiner les stats par mois de tous les blogs
|
||
|
|
stats_par_mois_combines = defaultdict(lambda: {
|
||
|
|
'articles': [],
|
||
|
|
'signes_total': 0,
|
||
|
|
'nb_articles': 0,
|
||
|
|
'mots_total': 0,
|
||
|
|
'liens_total': 0,
|
||
|
|
'liens_images_total': 0,
|
||
|
|
'liens_autres_total': 0,
|
||
|
|
'temps_lecture_total': 0
|
||
|
|
})
|
||
|
|
|
||
|
|
# Pour chaque blog, récupérer les stats par mois et additionner
|
||
|
|
for blog_data in blogs_data:
|
||
|
|
for mois_cle, stats_mois in blog_data['stats_par_mois'].items():
|
||
|
|
stats_par_mois_combines[mois_cle]['articles'].extend(stats_mois.get('articles', []))
|
||
|
|
stats_par_mois_combines[mois_cle]['signes_total'] += stats_mois.get('signes_total', 0)
|
||
|
|
stats_par_mois_combines[mois_cle]['nb_articles'] += stats_mois.get('nb_articles', 0)
|
||
|
|
stats_par_mois_combines[mois_cle]['mots_total'] += stats_mois.get('mots_total', 0)
|
||
|
|
stats_par_mois_combines[mois_cle]['liens_total'] += stats_mois.get('liens_total', 0)
|
||
|
|
stats_par_mois_combines[mois_cle]['liens_images_total'] += stats_mois.get('liens_images_total', 0)
|
||
|
|
stats_par_mois_combines[mois_cle]['liens_autres_total'] += stats_mois.get('liens_autres_total', 0)
|
||
|
|
stats_par_mois_combines[mois_cle]['temps_lecture_total'] += stats_mois.get('temps_lecture_total', 0)
|
||
|
|
|
||
|
|
# Calculer les stats NaNoWriMo pour les 3 derniers mois
|
||
|
|
return calculer_stats_nanowrimo(stats_par_mois_combines, None, objectif_quotidien, objectif_mensuel)
|
||
|
|
|
||
|
|
|
||
|
|
def generer_graphiques_combines(blogs_data, output_dir):
|
||
|
|
"""
|
||
|
|
Génère des graphiques combinés pour plusieurs blogs.
|
||
|
|
Crée un graphique en barres groupées montrant les articles par mois pour chaque blog avec des couleurs différentes.
|
||
|
|
"""
|
||
|
|
if not HAS_MATPLOTLIB:
|
||
|
|
return []
|
||
|
|
|
||
|
|
# Couleurs pour chaque blog (palette de couleurs distinctes)
|
||
|
|
couleurs = ['#4CAF50', '#2196F3', '#FF9800', '#9C27B0', '#F44336', '#00BCD4', '#FFEB3B', '#795548']
|
||
|
|
|
||
|
|
# Récupérer tous les mois de tous les blogs
|
||
|
|
tous_mois = set()
|
||
|
|
for blog_data in blogs_data:
|
||
|
|
for mois_cle in blog_data['stats_par_mois'].keys():
|
||
|
|
tous_mois.add(mois_cle)
|
||
|
|
|
||
|
|
if not tous_mois:
|
||
|
|
return []
|
||
|
|
|
||
|
|
# Trier les mois chronologiquement
|
||
|
|
mois_tries = sorted(tous_mois)
|
||
|
|
mois_dates = [datetime.strptime(m, '%Y-%m') for m in mois_tries]
|
||
|
|
|
||
|
|
# Créer le dossier pour les graphiques
|
||
|
|
graph_dir = os.path.join(output_dir, 'stats_graphs_combines')
|
||
|
|
os.makedirs(graph_dir, exist_ok=True)
|
||
|
|
|
||
|
|
graphiques = []
|
||
|
|
|
||
|
|
# Graphique 1: Articles par mois (barres groupées)
|
||
|
|
fig, ax = plt.subplots(figsize=(14, 8))
|
||
|
|
|
||
|
|
nb_blogs = len(blogs_data)
|
||
|
|
largeur_barre = 20 # Largeur de chaque groupe de barres
|
||
|
|
espacement = largeur_barre / nb_blogs # Espacement entre les barres dans un groupe
|
||
|
|
|
||
|
|
for i, blog_data in enumerate(blogs_data):
|
||
|
|
nb_articles_par_mois = []
|
||
|
|
for mois_cle in mois_tries:
|
||
|
|
stats_mois = blog_data['stats_par_mois'].get(mois_cle, {})
|
||
|
|
nb_articles_par_mois.append(len(stats_mois.get('articles', [])))
|
||
|
|
|
||
|
|
# Position des barres pour ce blog (décalage par rapport au centre)
|
||
|
|
positions = [mdates.date2num(m) - largeur_barre/2 + i * espacement + espacement/2 for m in mois_dates]
|
||
|
|
|
||
|
|
ax.bar(positions, nb_articles_par_mois, width=espacement*0.8,
|
||
|
|
label=blog_data['blog_title'], color=couleurs[i % len(couleurs)], alpha=0.7)
|
||
|
|
|
||
|
|
ax.set_xlabel('Mois', fontsize=12)
|
||
|
|
ax.set_ylabel('Nombre d\'articles', fontsize=12)
|
||
|
|
ax.set_title('Articles publiés par mois - Comparaison des blogs', fontsize=14, fontweight='bold')
|
||
|
|
ax.legend(loc='upper left')
|
||
|
|
ax.grid(True, alpha=0.3, axis='y')
|
||
|
|
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))
|
||
|
|
ax.xaxis.set_major_locator(mdates.MonthLocator(interval=max(1, len(mois_dates)//12)))
|
||
|
|
plt.xticks([mdates.date2num(m) for m in mois_dates], rotation=45, ha='right')
|
||
|
|
plt.tight_layout()
|
||
|
|
|
||
|
|
graph1_path = os.path.join(graph_dir, 'articles_par_mois_combines.png')
|
||
|
|
plt.savefig(graph1_path, dpi=150, bbox_inches='tight')
|
||
|
|
plt.close()
|
||
|
|
graphiques.append(('articles_par_mois_combines.png', 'Articles publiés par mois - Comparaison des blogs'))
|
||
|
|
|
||
|
|
if not graphiques:
|
||
|
|
return [], None
|
||
|
|
|
||
|
|
return graphiques, graph_dir
|
||
|
|
|
||
|
|
|
||
|
|
def generer_page_combinee(blogs_data, output_file, html_websites_dir, env, objectif_quotidien=None, objectif_mensuel=None):
|
||
|
|
"""
|
||
|
|
Génère une page HTML combinée pour plusieurs blogs.
|
||
|
|
"""
|
||
|
|
template_combined = env.get_template('templates/html/stats_combined.html.j2')
|
||
|
|
|
||
|
|
# Calculer les statistiques globales combinées
|
||
|
|
nb_articles_total = sum(data['nb_articles_total'] for data in blogs_data)
|
||
|
|
mots_total = sum(data['mots_total'] for data in blogs_data)
|
||
|
|
signes_total = sum(data['signes_total'] for data in blogs_data)
|
||
|
|
liens_total = sum(data['liens_total'] for data in blogs_data)
|
||
|
|
temps_lecture_total = sum(data['temps_lecture_total'] for data in blogs_data)
|
||
|
|
|
||
|
|
# Moyennes globales
|
||
|
|
mots_moyen = mots_total / nb_articles_total if nb_articles_total > 0 else 0
|
||
|
|
liens_moyen = liens_total / nb_articles_total if nb_articles_total > 0 else 0
|
||
|
|
signes_moyen = signes_total / nb_articles_total if nb_articles_total > 0 else 0
|
||
|
|
temps_lecture_par_article = temps_lecture_total / nb_articles_total if nb_articles_total > 0 else 0
|
||
|
|
|
||
|
|
# Calculer les statistiques NaNoWriMo combinées pour les 3 derniers mois
|
||
|
|
stats_nanowrimo_combines = calculer_nanowrimo_combine(blogs_data, objectif_quotidien, objectif_mensuel)
|
||
|
|
|
||
|
|
# Générer les graphiques combinés
|
||
|
|
graphiques_combines, graph_path_combines = generer_graphiques_combines(blogs_data, html_websites_dir)
|
||
|
|
|
||
|
|
# Copier le fichier CSS
|
||
|
|
css_source = 'templates/styles/stats.css'
|
||
|
|
css_dest = os.path.join(html_websites_dir, 'stats.css')
|
||
|
|
if os.path.exists(css_source):
|
||
|
|
shutil.copy2(css_source, css_dest)
|
||
|
|
|
||
|
|
# Générer le HTML
|
||
|
|
date_gen = datetime.now().strftime('%d/%m/%Y à %H:%M:%S')
|
||
|
|
blogs_list = ', '.join(data['blog_title'] for data in blogs_data)
|
||
|
|
page_title = ' | '.join(data['blog_title'] for data in blogs_data)
|
||
|
|
|
||
|
|
html_content = template_combined.render(
|
||
|
|
page_title=page_title,
|
||
|
|
blogs_list=blogs_list,
|
||
|
|
blogs_data=blogs_data,
|
||
|
|
nb_articles_total=nb_articles_total,
|
||
|
|
mots_total=mots_total,
|
||
|
|
signes_total=signes_total,
|
||
|
|
liens_total=liens_total,
|
||
|
|
temps_lecture_total=temps_lecture_total,
|
||
|
|
mots_moyen=mots_moyen,
|
||
|
|
liens_moyen=liens_moyen,
|
||
|
|
signes_moyen=signes_moyen,
|
||
|
|
temps_lecture_par_article=temps_lecture_par_article,
|
||
|
|
stats_nanowrimo_combines=stats_nanowrimo_combines,
|
||
|
|
objectif_quotidien_custom=objectif_quotidien,
|
||
|
|
objectif_mensuel_custom=objectif_mensuel,
|
||
|
|
graphiques_combines=graphiques_combines,
|
||
|
|
graph_path_combines='stats_graphs_combines' if graphiques_combines else None,
|
||
|
|
date_gen=date_gen,
|
||
|
|
lecture_mots_par_minute=LECTURE_MOTS_PAR_MINUTE,
|
||
|
|
css_path='stats.css'
|
||
|
|
)
|
||
|
|
|
||
|
|
# Sauvegarder le HTML
|
||
|
|
html_path = os.path.join(html_websites_dir, output_file)
|
||
|
|
with open(html_path, 'w', encoding='utf-8') as f:
|
||
|
|
f.write(html_content)
|
||
|
|
|
||
|
|
print(f"\n✓ Page combinée générée: {html_path}")
|
||
|
|
|
||
|
|
|
||
|
|
def main():
|
||
|
|
"""
|
||
|
|
Fonction principale qui analyse les blogs et génère les pages de statistiques.
|
||
|
|
"""
|
||
|
|
parser = argparse.ArgumentParser(
|
||
|
|
description='Génère des statistiques détaillées sur les blogs'
|
||
|
|
)
|
||
|
|
parser.add_argument(
|
||
|
|
'blogs',
|
||
|
|
nargs='*',
|
||
|
|
help='Noms des blogs à analyser (si vide, analyse tous les blogs)'
|
||
|
|
)
|
||
|
|
parser.add_argument(
|
||
|
|
'--output',
|
||
|
|
'-o',
|
||
|
|
help='Nom du fichier de sortie pour une page combinée (ex: tk_combinaison_stats.html)'
|
||
|
|
)
|
||
|
|
parser.add_argument(
|
||
|
|
'--objectif-articles',
|
||
|
|
type=int,
|
||
|
|
help='Objectif de nombre d\'articles pour le mois courant (par défaut: moyenne mensuelle)'
|
||
|
|
)
|
||
|
|
parser.add_argument(
|
||
|
|
'--objectif-signes-quotidien',
|
||
|
|
type=int,
|
||
|
|
help='Objectif de signes par jour (prend le pas sur l\'objectif NaNoWriMo par défaut de 1667)'
|
||
|
|
)
|
||
|
|
parser.add_argument(
|
||
|
|
'--objectif-signes-mensuel',
|
||
|
|
type=int,
|
||
|
|
help='Objectif de signes par mois (prend le pas sur l\'objectif quotidien et NaNoWriMo)'
|
||
|
|
)
|
||
|
|
|
||
|
|
args = parser.parse_args()
|
||
|
|
|
||
|
|
sources_dir = "sources"
|
||
|
|
html_websites_dir = "html-websites"
|
||
|
|
|
||
|
|
# Configurer Jinja2
|
||
|
|
env = Environment(loader=FileSystemLoader('.'))
|
||
|
|
|
||
|
|
# Ajouter des filtres personnalisés pour le template
|
||
|
|
env.filters['format_duree'] = formater_duree
|
||
|
|
env.filters['format_number'] = format_number
|
||
|
|
|
||
|
|
template = env.get_template('templates/html/stats.html.j2')
|
||
|
|
|
||
|
|
# Lister tous les dossiers de blogs si aucun n'est spécifié
|
||
|
|
if not os.path.exists(sources_dir):
|
||
|
|
print(f"Erreur: Le dossier {sources_dir} n'existe pas")
|
||
|
|
return
|
||
|
|
|
||
|
|
if args.blogs:
|
||
|
|
blogs = args.blogs
|
||
|
|
else:
|
||
|
|
blogs = [d for d in os.listdir(sources_dir)
|
||
|
|
if os.path.isdir(os.path.join(sources_dir, d))
|
||
|
|
and d not in ['.', '..']]
|
||
|
|
|
||
|
|
print(f"Blogs à analyser: {', '.join(blogs)}\n")
|
||
|
|
|
||
|
|
# Calculer l'objectif d'articles par défaut (moyenne mensuelle) si non spécifié
|
||
|
|
objectif_articles = args.objectif_articles
|
||
|
|
if objectif_articles is None:
|
||
|
|
# Calculer la moyenne mensuelle sur tous les blogs
|
||
|
|
total_articles = 0
|
||
|
|
total_mois = 0
|
||
|
|
for blog_name in blogs:
|
||
|
|
blog_path = os.path.join(sources_dir, blog_name)
|
||
|
|
articles = analyser_blog(blog_path)
|
||
|
|
if articles:
|
||
|
|
stats_par_mois = calculer_statistiques_par_mois(articles)
|
||
|
|
total_articles += len(articles)
|
||
|
|
total_mois += len(stats_par_mois)
|
||
|
|
if total_mois > 0:
|
||
|
|
objectif_articles = int(total_articles / total_mois)
|
||
|
|
print(f"Objectif d'articles par défaut (moyenne mensuelle): {objectif_articles}\n")
|
||
|
|
|
||
|
|
# Récupérer les objectifs de signes personnalisés
|
||
|
|
objectif_quotidien = args.objectif_signes_quotidien
|
||
|
|
objectif_mensuel = args.objectif_signes_mensuel
|
||
|
|
|
||
|
|
# Si un fichier de sortie est spécifié, générer une page combinée
|
||
|
|
if args.output:
|
||
|
|
blogs_data = []
|
||
|
|
for blog_name in blogs:
|
||
|
|
print(f"Analyse de {blog_name}...")
|
||
|
|
data = generer_statistiques_blog(blog_name, sources_dir, html_websites_dir, env, template,
|
||
|
|
objectif_articles, objectif_quotidien, objectif_mensuel)
|
||
|
|
if data:
|
||
|
|
blogs_data.append(data)
|
||
|
|
print()
|
||
|
|
|
||
|
|
if blogs_data:
|
||
|
|
generer_page_combinee(blogs_data, args.output, html_websites_dir, env, objectif_quotidien, objectif_mensuel)
|
||
|
|
else:
|
||
|
|
print("Aucune donnée à combiner.")
|
||
|
|
else:
|
||
|
|
# Générer une page pour chaque blog
|
||
|
|
for blog_name in blogs:
|
||
|
|
print(f"Analyse de {blog_name}...")
|
||
|
|
generer_statistiques_blog(blog_name, sources_dir, html_websites_dir, env, template,
|
||
|
|
objectif_articles, objectif_quotidien, objectif_mensuel)
|
||
|
|
print()
|
||
|
|
|
||
|
|
print("Terminé!")
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|