svg_cache_manager.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. """SVG Cache Manager for pre-generating and managing SVG previews."""
  2. import os
  3. import json
  4. import asyncio
  5. import logging
  6. from pathlib import Path
  7. from modules.core.pattern_manager import list_theta_rho_files, THETA_RHO_DIR
  8. logger = logging.getLogger(__name__)
  9. # Constants
  10. CACHE_DIR = os.path.join(THETA_RHO_DIR, "cached_svg")
  11. def ensure_cache_dir():
  12. """Ensure the cache directory exists with proper permissions."""
  13. try:
  14. Path(CACHE_DIR).mkdir(parents=True, exist_ok=True)
  15. # Walk through the cache directory and set permissions for all files and subdirectories
  16. for root, dirs, files in os.walk(CACHE_DIR):
  17. try:
  18. # Set 777 for directories
  19. os.chmod(root, 0o777)
  20. # Set 666 for files
  21. for file in files:
  22. file_path = os.path.join(root, file)
  23. try:
  24. os.chmod(file_path, 0o666)
  25. except Exception as e:
  26. logger.error(f"Failed to set permissions for file {file_path}: {str(e)}")
  27. except Exception as e:
  28. logger.error(f"Failed to set permissions for directory {root}: {str(e)}")
  29. continue
  30. except Exception as e:
  31. logger.error(f"Failed to set cache directory permissions: {str(e)}")
  32. # Continue even if permissions can't be set
  33. pass
  34. def get_cache_path(pattern_file):
  35. """Get the cache path for a pattern file."""
  36. # Convert the pattern file path to a safe filename
  37. safe_name = pattern_file.replace('/', '_').replace('\\', '_')
  38. return os.path.join(CACHE_DIR, f"{safe_name}.svg")
  39. def needs_cache(pattern_file):
  40. """Check if a pattern file needs its cache generated."""
  41. cache_path = get_cache_path(pattern_file)
  42. return not os.path.exists(cache_path)
  43. async def generate_svg_preview(pattern_file):
  44. """Generate SVG preview for a single pattern file."""
  45. from modules.core.preview import generate_preview_svg
  46. try:
  47. # Generate the SVG
  48. svg_content = await generate_preview_svg(pattern_file)
  49. # Save to cache
  50. cache_path = get_cache_path(pattern_file)
  51. with open(cache_path, 'w', encoding='utf-8') as f:
  52. f.write(svg_content)
  53. # Set file permissions to 666 to allow any user to read/write
  54. try:
  55. os.chmod(cache_path, 0o666)
  56. except Exception as e:
  57. logger.error(f"Failed to set cache file permissions for {pattern_file}: {str(e)}")
  58. # Continue even if permissions can't be set
  59. pass
  60. return True
  61. except Exception as e:
  62. # Only log the error message, not the full SVG content
  63. logger.error(f"Failed to generate SVG for {pattern_file}")
  64. return False
  65. async def generate_all_svg_previews():
  66. """Generate SVG previews for all pattern files."""
  67. ensure_cache_dir()
  68. # Get all pattern files and filter for .thr files only
  69. pattern_files = [f for f in list_theta_rho_files() if f.endswith('.thr')]
  70. # Filter out patterns that already have cache
  71. patterns_to_cache = [f for f in pattern_files if needs_cache(f)]
  72. total_files = len(patterns_to_cache)
  73. if total_files == 0:
  74. logger.info("All patterns are already cached")
  75. return
  76. logger.info(f"Generating SVG cache for {total_files} uncached .thr patterns...")
  77. # Process files concurrently in batches to avoid overwhelming the system
  78. batch_size = 5
  79. successful = 0
  80. for i in range(0, total_files, batch_size):
  81. batch = patterns_to_cache[i:i + batch_size]
  82. tasks = [generate_svg_preview(file) for file in batch]
  83. results = await asyncio.gather(*tasks)
  84. successful += sum(1 for r in results if r)
  85. logger.info(f"SVG cache generation completed: {successful}/{total_files} patterns cached")