""" Google Ads Integration Handles displaying Google AdSense ads and tracking ad impressions/clicks """ import os import uuid import logging import json import time from typing import Dict, Any, Optional, List from datetime import datetime # Setup logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger("google_ads") class GoogleAdsManager: """Manages Google AdSense integration and tracking""" def __init__(self, publisher_id: Optional[str] = None, config_file: str = None): """Initialize Google Ads Manager""" self.publisher_id = publisher_id or os.getenv("GOOGLE_ADSENSE_PUBLISHER_ID", "") self.config_file = config_file or os.path.join(os.path.dirname(__file__), "ads_config.json") # Load ad units configuration self.ad_units = self._load_ad_units() # Track impressions and clicks self.impressions_file = os.path.join(os.path.dirname(__file__), "impressions.json") self.clicks_file = os.path.join(os.path.dirname(__file__), "clicks.json") # Create tracking files if they don't exist self._initialize_tracking_files() def _load_ad_units(self) -> Dict[str, Any]: """Load ad units configuration""" default_ad_units = { "sidebar": { "ad_unit_id": "1234567890", "ad_format": "display", "width": 300, "height": 250, "slot": "sidebar-ad", "enabled": True }, "footer": { "ad_unit_id": "0987654321", "ad_format": "display", "width": 728, "height": 90, "slot": "footer-ad", "enabled": True }, "reward_video": { "ad_unit_id": "5678901234", "ad_format": "video", "slot": "reward-video-ad", "enabled": True, "reward_credits": 10 } } # Create config file with default values if it doesn't exist if not os.path.exists(self.config_file): os.makedirs(os.path.dirname(self.config_file), exist_ok=True) with open(self.config_file, "w") as f: json.dump({"publisher_id": self.publisher_id, "ad_units": default_ad_units}, f, indent=2) return default_ad_units # Load config from file try: with open(self.config_file, "r") as f: config = json.load(f) # Update publisher ID if it was set in the config file if config.get("publisher_id"): self.publisher_id = config["publisher_id"] return config.get("ad_units", default_ad_units) except Exception as e: logger.error(f"Error loading ad units config: {e}") return default_ad_units def _initialize_tracking_files(self): """Initialize tracking files if they don't exist""" os.makedirs(os.path.dirname(self.impressions_file), exist_ok=True) if not os.path.exists(self.impressions_file): with open(self.impressions_file, "w") as f: json.dump([], f) if not os.path.exists(self.clicks_file): with open(self.clicks_file, "w") as f: json.dump([], f) def get_ad_code(self, ad_position: str) -> Dict[str, Any]: """ Get HTML/JS code for displaying an ad at the specified position Returns both the ad code and metadata about the ad """ if not self.publisher_id: logger.warning("No Google AdSense publisher ID configured") return {"success": False, "error": "No publisher ID configured"} # Get ad unit configuration ad_unit = self.ad_units.get(ad_position) if not ad_unit: logger.error(f"Ad position '{ad_position}' not configured") return {"success": False, "error": f"Ad position '{ad_position}' not found"} if not ad_unit.get("enabled", True): logger.info(f"Ad unit '{ad_position}' is disabled") return {"success": False, "error": "Ad unit is disabled"} # Generate HTML/JS code for the ad ad_format = ad_unit.get("ad_format", "display") ad_unit_id = ad_unit.get("ad_unit_id", "") ad_slot = ad_unit.get("slot", f"{ad_position}-ad") if ad_format == "display": width = ad_unit.get("width", 300) height = ad_unit.get("height", 250) ad_code = f""" """ elif ad_format == "video": ad_code = f"""

Watch a video to earn {ad_unit.get('reward_credits', 5)} credits

""" else: logger.error(f"Unsupported ad format: {ad_format}") return {"success": False, "error": f"Unsupported ad format: {ad_format}"} # Generate a unique ID for tracking this ad impression impression_id = str(uuid.uuid4()) # Record the impression for tracking self._record_impression(impression_id, ad_position, ad_unit_id) return { "success": True, "ad_code": ad_code, "impression_id": impression_id, "ad_position": ad_position, "ad_format": ad_format, "reward_credits": ad_unit.get("reward_credits", 0) if ad_format == "video" else 0 } def _record_impression(self, impression_id: str, ad_position: str, ad_unit_id: str): """Record an ad impression for tracking""" try: # Load existing impressions with open(self.impressions_file, "r") as f: impressions = json.load(f) # Add new impression impressions.append({ "id": impression_id, "timestamp": datetime.now().isoformat(), "ad_position": ad_position, "ad_unit_id": ad_unit_id }) # Save updated impressions with open(self.impressions_file, "w") as f: json.dump(impressions, f, indent=2) except Exception as e: logger.error(f"Error recording ad impression: {e}") def record_ad_click(self, impression_id: str, user_id: Optional[str] = None) -> bool: """Record an ad click for tracking""" try: # Load existing clicks with open(self.clicks_file, "r") as f: clicks = json.load(f) # Add new click clicks.append({ "impression_id": impression_id, "user_id": user_id, "timestamp": datetime.now().isoformat() }) # Save updated clicks with open(self.clicks_file, "w") as f: json.dump(clicks, f, indent=2) return True except Exception as e: logger.error(f"Error recording ad click: {e}") return False def record_reward_ad_completion(self, impression_id: str, user_id: str) -> Dict[str, Any]: """ Record completion of a reward ad and return reward information Args: impression_id: The unique ID of the ad impression user_id: The user ID to reward Returns: Dictionary with reward information and success status """ try: # Find the impression to determine the ad unit with open(self.impressions_file, "r") as f: impressions = json.load(f) # Find the impression with matching ID impression = next((imp for imp in impressions if imp.get("id") == impression_id), None) if not impression: logger.error(f"Impression ID {impression_id} not found") return { "success": False, "error": "Invalid impression ID" } # Get the ad position from the impression ad_position = impression.get("ad_position") ad_unit = self.ad_units.get(ad_position) if not ad_unit: logger.error(f"Ad unit for position {ad_position} not found") return { "success": False, "error": "Ad unit not found" } # Get the reward amount reward_credits = ad_unit.get("reward_credits", 0) # Record the ad completion (we could store this in a separate file) self.record_ad_click(impression_id, user_id) return { "success": True, "reward_credits": reward_credits, "user_id": user_id, "impression_id": impression_id, "timestamp": datetime.now().isoformat() } except Exception as e: logger.error(f"Error processing reward ad completion: {e}") return { "success": False, "error": str(e) } def get_html_header_code(self) -> str: """Get the HTML code to include in the page header for AdSense""" if not self.publisher_id: return "" return f""" """ def get_reward_ad_js(self) -> str: """Get the JavaScript code for handling reward ads""" return """ """ # Example usage if __name__ == "__main__": # Initialize the ads manager ads_manager = GoogleAdsManager() # Get ad code for the sidebar sidebar_ad = ads_manager.get_ad_code("sidebar") print(f"Sidebar ad success: {sidebar_ad['success']}") if sidebar_ad['success']: print(f"Impression ID: {sidebar_ad['impression_id']}") # Get the header code for AdSense header_code = ads_manager.get_html_header_code() print(f"Header code length: {len(header_code)}")