mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-04-10 21:03:01 +00:00
Move YouTube API key and channel ID to secrets file for better security
This commit is contained in:
@@ -12,43 +12,46 @@ from typing import Dict, Any
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class YouTubeDisplay:
|
||||
def __init__(self, display_manager, config_path='config/config.json', secrets_path='config/config_secrets.json'):
|
||||
self.config = self._load_config(config_path)
|
||||
self.secrets = self._load_config(secrets_path)
|
||||
self.matrix = self._setup_matrix()
|
||||
self.canvas = self.matrix.CreateFrameCanvas()
|
||||
self.font = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
|
||||
self.youtube_logo = Image.open("assets/youtube_logo.png")
|
||||
def __init__(self, display_manager, config: Dict[str, Any]):
|
||||
self.display_manager = display_manager
|
||||
self.config = config
|
||||
self.youtube_config = config.get('youtube', {})
|
||||
self.enabled = self.youtube_config.get('enabled', False)
|
||||
self.update_interval = self.youtube_config.get('update_interval', 300)
|
||||
self.last_update = 0
|
||||
self.update_interval = self.config.get('youtube', {}).get('update_interval', 300) # Default 5 minutes
|
||||
self.channel_stats = None
|
||||
|
||||
def _load_config(self, config_path):
|
||||
with open(config_path, 'r') as f:
|
||||
return json.load(f)
|
||||
# Load secrets file
|
||||
try:
|
||||
with open('config/config_secrets.json', 'r') as f:
|
||||
self.secrets = json.load(f)
|
||||
except Exception as e:
|
||||
logger.error(f"Error loading secrets file: {e}")
|
||||
self.secrets = {}
|
||||
self.enabled = False
|
||||
|
||||
if self.enabled:
|
||||
logger.info("YouTube display enabled")
|
||||
self._initialize_display()
|
||||
else:
|
||||
logger.info("YouTube display disabled")
|
||||
|
||||
def _initialize_display(self):
|
||||
"""Initialize display components."""
|
||||
self.font = ImageFont.truetype("assets/fonts/PressStart2P-Regular.ttf", 8)
|
||||
try:
|
||||
self.youtube_logo = Image.open("assets/youtube_logo.png")
|
||||
except Exception as e:
|
||||
logger.error(f"Error loading YouTube logo: {e}")
|
||||
self.enabled = False
|
||||
|
||||
def _setup_matrix(self):
|
||||
options = RGBMatrixOptions()
|
||||
display_config = self.config['display']['hardware']
|
||||
|
||||
options.rows = display_config['rows']
|
||||
options.cols = display_config['cols']
|
||||
options.chain_length = display_config['chain_length']
|
||||
options.parallel = display_config['parallel']
|
||||
options.hardware_mapping = display_config['hardware_mapping']
|
||||
options.brightness = display_config['brightness']
|
||||
options.pwm_bits = display_config['pwm_bits']
|
||||
options.pwm_lsb_nanoseconds = display_config['pwm_lsb_nanoseconds']
|
||||
options.disable_hardware_pulsing = display_config['disable_hardware_pulsing']
|
||||
options.show_refresh_rate = display_config['show_refresh_rate']
|
||||
options.limit_refresh_rate_hz = display_config['limit_refresh_rate_hz']
|
||||
options.gpio_slowdown = self.config['display']['runtime']['gpio_slowdown']
|
||||
|
||||
return RGBMatrix(options=options)
|
||||
|
||||
def _get_channel_stats(self, channel_id):
|
||||
api_key = self.secrets['youtube']['api_key']
|
||||
"""Fetch channel statistics from YouTube API."""
|
||||
api_key = self.secrets.get('youtube', {}).get('api_key')
|
||||
if not api_key:
|
||||
logger.error("YouTube API key not configured in secrets file")
|
||||
return None
|
||||
|
||||
url = f"https://www.googleapis.com/youtube/v3/channels?part=statistics,snippet&id={channel_id}&key={api_key}"
|
||||
|
||||
try:
|
||||
@@ -66,51 +69,73 @@ class YouTubeDisplay:
|
||||
return None
|
||||
|
||||
def _create_display(self, channel_stats):
|
||||
"""Create the display image with channel statistics."""
|
||||
if not channel_stats:
|
||||
return None
|
||||
|
||||
# Create a new image with the matrix dimensions
|
||||
image = Image.new('RGB', (self.matrix.width, self.matrix.height))
|
||||
image = Image.new('RGB', (self.display_manager.matrix.width, self.display_manager.matrix.height))
|
||||
draw = ImageDraw.Draw(image)
|
||||
|
||||
# Resize YouTube logo to fit
|
||||
logo_height = self.matrix.height // 3
|
||||
# Resize YouTube logo to fill 75% of display height
|
||||
logo_height = int(self.display_manager.matrix.height * 0.75)
|
||||
logo_width = int(self.youtube_logo.width * (logo_height / self.youtube_logo.height))
|
||||
resized_logo = self.youtube_logo.resize((logo_width, logo_height))
|
||||
|
||||
# Calculate positions
|
||||
logo_x = (self.matrix.width - logo_width) // 2
|
||||
logo_y = 0
|
||||
# Position logo on the left
|
||||
logo_x = 2 # Small padding from left edge
|
||||
logo_y = (self.display_manager.matrix.height - logo_height) // 2 # Center vertically
|
||||
|
||||
# Paste the logo
|
||||
image.paste(resized_logo, (logo_x, logo_y))
|
||||
|
||||
# Draw channel name
|
||||
# Calculate right section width (remaining space after logo)
|
||||
right_section_x = logo_x + logo_width + 5 # Start after logo with some padding
|
||||
|
||||
# Draw channel name (top right)
|
||||
channel_name = channel_stats['title']
|
||||
name_bbox = draw.textbbox((0, 0), channel_name, font=self.font)
|
||||
name_width = name_bbox[2] - name_bbox[0]
|
||||
name_x = (self.matrix.width - name_width) // 2
|
||||
name_y = logo_height + 5
|
||||
name_x = right_section_x + ((self.display_manager.matrix.width - right_section_x - name_width) // 2)
|
||||
name_y = 5 # Small padding from top
|
||||
draw.text((name_x, name_y), channel_name, font=self.font, fill=(255, 255, 255))
|
||||
|
||||
# Draw subscriber count
|
||||
# Draw subscriber count (middle right)
|
||||
subs_text = f"{channel_stats['subscribers']:,} subscribers"
|
||||
subs_bbox = draw.textbbox((0, 0), subs_text, font=self.font)
|
||||
subs_width = subs_bbox[2] - subs_bbox[0]
|
||||
subs_x = (self.matrix.width - subs_width) // 2
|
||||
subs_y = name_y + 15
|
||||
subs_x = right_section_x + ((self.display_manager.matrix.width - right_section_x - subs_width) // 2)
|
||||
subs_y = name_y + 15 # Position below channel name
|
||||
draw.text((subs_x, subs_y), subs_text, font=self.font, fill=(255, 255, 255))
|
||||
|
||||
# Draw view count (bottom right)
|
||||
views_text = f"{channel_stats['views']:,} views"
|
||||
views_bbox = draw.textbbox((0, 0), views_text, font=self.font)
|
||||
views_width = views_bbox[2] - views_bbox[0]
|
||||
views_x = right_section_x + ((self.display_manager.matrix.width - right_section_x - views_width) // 2)
|
||||
views_y = subs_y + 15 # Position below subscriber count
|
||||
draw.text((views_x, views_y), views_text, font=self.font, fill=(255, 255, 255))
|
||||
|
||||
return image
|
||||
|
||||
def update(self):
|
||||
"""Update YouTube channel stats if needed."""
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
current_time = time.time()
|
||||
if current_time - self.last_update >= self.update_interval:
|
||||
channel_id = self.secrets['youtube']['channel_id']
|
||||
channel_id = self.config.get('youtube', {}).get('channel_id')
|
||||
if not channel_id:
|
||||
logger.error("YouTube channel ID not configured")
|
||||
return
|
||||
|
||||
self.channel_stats = self._get_channel_stats(channel_id)
|
||||
self.last_update = current_time
|
||||
|
||||
def display(self, force_clear: bool = False):
|
||||
"""Display YouTube channel stats."""
|
||||
if not self.config.get('youtube', {}).get('enabled', False):
|
||||
if not self.enabled:
|
||||
return
|
||||
|
||||
if not self.channel_stats:
|
||||
@@ -118,15 +143,17 @@ class YouTubeDisplay:
|
||||
|
||||
if self.channel_stats:
|
||||
if force_clear:
|
||||
self.matrix.Clear()
|
||||
self.display_manager.clear()
|
||||
|
||||
display_image = self._create_display(self.channel_stats)
|
||||
self.canvas.SetImage(display_image)
|
||||
self.matrix.SwapOnVSync(self.canvas)
|
||||
time.sleep(self.update_interval)
|
||||
if display_image:
|
||||
self.display_manager.image = display_image
|
||||
self.display_manager.update_display()
|
||||
|
||||
def cleanup(self):
|
||||
self.matrix.Clear()
|
||||
"""Clean up resources."""
|
||||
if self.enabled:
|
||||
self.display_manager.clear()
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Example usage
|
||||
|
||||
Reference in New Issue
Block a user