Add scripts/report_generator.py
Some checks failed
📺 Generate M3U Playlist / build (push) Has been cancelled
Some checks failed
📺 Generate M3U Playlist / build (push) Has been cancelled
This commit is contained in:
parent
c6d5674ce2
commit
8c7ee2416c
1 changed files with 133 additions and 0 deletions
133
scripts/report_generator.py
Normal file
133
scripts/report_generator.py
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
"""
|
||||||
|
Report Generator - Creates comprehensive reports and statistics
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Dict, Optional
|
||||||
|
|
||||||
|
class ReportGenerator:
|
||||||
|
"""Generate comprehensive reports and statistics."""
|
||||||
|
|
||||||
|
def __init__(self, config):
|
||||||
|
self.config = config
|
||||||
|
self.logger = logging.getLogger(__name__)
|
||||||
|
self.reports_dir = Path("reports")
|
||||||
|
self.reports_dir.mkdir(exist_ok=True)
|
||||||
|
|
||||||
|
def generate_markdown_report(self, stats: Dict, health_results: Dict = None) -> str:
|
||||||
|
"""Generate a detailed Markdown report."""
|
||||||
|
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
|
||||||
|
report_lines = [
|
||||||
|
"# IPTV Playlist Generation Report",
|
||||||
|
f"**Generated:** {timestamp}\n",
|
||||||
|
"## Summary Statistics",
|
||||||
|
f"- **Total channels processed:** {stats.get('total_channels', 0)}",
|
||||||
|
f"- **Valid channels:** {stats.get('valid_channels', 0)}",
|
||||||
|
f"- **Duplicates removed:** {stats.get('duplicates_removed', 0)}",
|
||||||
|
f"- **New channels imported:** {stats.get('imported_channels', 0)}",
|
||||||
|
f"- **Countries detected:** {stats.get('countries_detected', 0)}",
|
||||||
|
""
|
||||||
|
]
|
||||||
|
|
||||||
|
# Health check section
|
||||||
|
if health_results:
|
||||||
|
healthy_count = sum(1 for is_healthy, _ in health_results.values() if is_healthy)
|
||||||
|
total_checked = len(health_results)
|
||||||
|
success_rate = (healthy_count / total_checked * 100) if total_checked > 0 else 0
|
||||||
|
|
||||||
|
report_lines.extend([
|
||||||
|
"## Health Check Results",
|
||||||
|
f"- **Channels checked:** {total_checked}",
|
||||||
|
f"- **Healthy channels:** {healthy_count}",
|
||||||
|
f"- **Success rate:** {success_rate:.1f}%",
|
||||||
|
""
|
||||||
|
])
|
||||||
|
|
||||||
|
# Failed channels
|
||||||
|
failed_channels = [name for name, (is_healthy, status) in health_results.items() if not is_healthy]
|
||||||
|
if failed_channels:
|
||||||
|
report_lines.extend([
|
||||||
|
"### Failed Channels",
|
||||||
|
*[f"- {channel}" for channel in failed_channels[:10]], # Limit to first 10
|
||||||
|
""
|
||||||
|
])
|
||||||
|
|
||||||
|
# Country distribution
|
||||||
|
if 'country_distribution' in stats and stats['country_distribution']:
|
||||||
|
sorted_countries = sorted(
|
||||||
|
stats['country_distribution'].items(),
|
||||||
|
key=lambda x: x[1],
|
||||||
|
reverse=True
|
||||||
|
)
|
||||||
|
|
||||||
|
report_lines.extend([
|
||||||
|
"## Channel Distribution by Country",
|
||||||
|
*[f"- **{country}:** {count} channels" for country, count in sorted_countries],
|
||||||
|
""
|
||||||
|
])
|
||||||
|
|
||||||
|
# Configuration summary
|
||||||
|
report_lines.extend([
|
||||||
|
"## Configuration",
|
||||||
|
f"- **Remove duplicates:** {self.config.settings.get('remove_duplicates', 'Unknown')}",
|
||||||
|
f"- **Auto country detection:** {self.config.settings.get('auto_detect_country', 'Unknown')}",
|
||||||
|
f"- **Quality detection:** {self.config.settings.get('detect_quality', 'Unknown')}",
|
||||||
|
f"- **Adult content filtering:** {self.config.settings.get('skip_adult_content', 'Unknown')}",
|
||||||
|
f"- **Health check enabled:** {self.config.settings.get('enable_health_check', 'Unknown')}",
|
||||||
|
""
|
||||||
|
])
|
||||||
|
|
||||||
|
return "\n".join(report_lines)
|
||||||
|
|
||||||
|
def save_report(self, stats: Dict, health_results: Dict = None) -> Optional[Path]:
|
||||||
|
"""Save the report to a file."""
|
||||||
|
try:
|
||||||
|
report_content = self.generate_markdown_report(stats, health_results)
|
||||||
|
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||||||
|
report_path = self.reports_dir / f"playlist_report_{timestamp}.md"
|
||||||
|
|
||||||
|
with open(report_path, 'w', encoding='utf-8') as f:
|
||||||
|
f.write(report_content)
|
||||||
|
|
||||||
|
self.logger.info(f"Report saved: {report_path}")
|
||||||
|
|
||||||
|
# Cleanup old reports (keep last 10)
|
||||||
|
self._cleanup_old_reports()
|
||||||
|
|
||||||
|
return report_path
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Failed to save report: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _cleanup_old_reports(self):
|
||||||
|
"""Remove old reports, keeping only the most recent ones."""
|
||||||
|
try:
|
||||||
|
report_files = sorted(
|
||||||
|
[f for f in self.reports_dir.glob("playlist_report_*.md") if f.is_file()],
|
||||||
|
key=lambda x: x.stat().st_mtime,
|
||||||
|
reverse=True
|
||||||
|
)
|
||||||
|
|
||||||
|
# Keep last 10 reports
|
||||||
|
for old_report in report_files[10:]:
|
||||||
|
old_report.unlink()
|
||||||
|
self.logger.debug(f"Removed old report: {old_report}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.warning(f"Could not cleanup old reports: {e}")
|
||||||
|
|
||||||
|
def log_summary_stats(self, stats: Dict):
|
||||||
|
"""Log a quick summary to console/log."""
|
||||||
|
self.logger.info("=" * 50)
|
||||||
|
self.logger.info("PLAYLIST GENERATION SUMMARY")
|
||||||
|
self.logger.info("=" * 50)
|
||||||
|
self.logger.info(f"Total channels: {stats.get('total_channels', 0)}")
|
||||||
|
self.logger.info(f"Valid channels: {stats.get('valid_channels', 0)}")
|
||||||
|
self.logger.info(f"Duplicates removed: {stats.get('duplicates_removed', 0)}")
|
||||||
|
self.logger.info(f"New imports: {stats.get('imported_channels', 0)}")
|
||||||
|
self.logger.info(f"Countries: {stats.get('countries_detected', 0)}")
|
||||||
|
self.logger.info("=" * 50)
|
Loading…
Add table
Add a link
Reference in a new issue