SEO_Metadata_Analyzer / preview_generators.py
Waseem7711's picture
Create preview_generators.py
874bbda verified
raw
history blame
14.5 kB
import html
from urllib.parse import urlparse
class PreviewGenerator:
def __init__(self, metadata):
self.metadata = metadata
def generate_google_preview(self, url):
"""Generate Google search result preview"""
title = self.metadata.get('title', 'Untitled Page')
description = self.metadata.get('description', 'No description available.')
# Truncate title and description for Google display
display_title = title[:60] + "..." if len(title) > 60 else title
display_description = description[:160] + "..." if len(description) > 160 else description
# Parse URL for display
parsed_url = urlparse(url)
display_url = f"{parsed_url.netloc}{parsed_url.path}"
preview_html = f"""
<div class="preview-card" style="
font-family: arial, sans-serif;
max-width: 100%;
width: 100%;
margin: 10px 0;
padding: 15px;
border: 1px solid #e0e0e0;
border-radius: 8px;
background-color: #ffffff;
box-sizing: border-box;
overflow-wrap: break-word;
">
<div style="
color: #1a0dab;
font-size: clamp(16px, 4vw, 20px);
line-height: 1.3;
margin-bottom: 2px;
text-decoration: none;
word-break: break-word;
">
{html.escape(display_title)}
</div>
<div style="
color: #006621;
font-size: clamp(12px, 3vw, 14px);
line-height: 1.3;
margin-bottom: 5px;
word-break: break-all;
">
{html.escape(display_url)}
</div>
<div style="
color: #545454;
font-size: clamp(12px, 3vw, 14px);
line-height: 1.4;
word-break: break-word;
">
{html.escape(display_description)}
</div>
</div>
"""
return preview_html
def generate_facebook_preview(self, url):
"""Generate Facebook preview"""
title = self.metadata.get('og:title') or self.metadata.get('title', 'Untitled Page')
description = self.metadata.get('og:description') or self.metadata.get('description', 'No description available.')
image = self.metadata.get('og:image', '')
site_name = self.metadata.get('og:site_name', '')
# Parse URL for display
parsed_url = urlparse(url)
display_url = parsed_url.netloc.upper()
preview_html = f"""
<div class="preview-card" style="
font-family: Helvetica, Arial, sans-serif;
max-width: 100%;
width: 100%;
border: 1px solid #e1e5e9;
border-radius: 8px;
overflow: hidden;
background-color: #ffffff;
margin: 10px 0;
box-sizing: border-box;
">
"""
# Image section with better design
if image:
preview_html += f"""
<div style="
width: 100%;
height: clamp(200px, 30vw, 261px);
background: linear-gradient(135deg, #4267B2 0%, #898F9C 100%);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: white;
font-size: clamp(12px, 3vw, 14px);
position: relative;
overflow: hidden;
">
<div style="
background: rgba(255,255,255,0.1);
border-radius: 12px;
padding: 1rem;
text-align: center;
backdrop-filter: blur(10px);
border: 1px solid rgba(255,255,255,0.2);
max-width: 80%;
">
<div style="font-size: 2rem; margin-bottom: 0.5rem;">πŸ–ΌοΈ</div>
<div style="font-weight: 500; word-break: break-all;">
{html.escape(image[:50] + "..." if len(image) > 50 else image)}
</div>
</div>
</div>
"""
else:
preview_html += f"""
<div style="
width: 100%;
height: clamp(150px, 20vw, 200px);
background: linear-gradient(135deg, #f0f2f5 0%, #e4e6ea 100%);
display: flex;
align-items: center;
justify-content: center;
color: #65676b;
font-size: clamp(12px, 3vw, 14px);
border-bottom: 1px solid #e4e6ea;
">
<div style="text-align: center; opacity: 0.7;">
<div style="font-size: 2rem; margin-bottom: 0.5rem;">πŸ“·</div>
<div>No image available</div>
</div>
</div>
"""
# Content section with enhanced design
preview_html += f"""
<div style="
padding: clamp(12px, 3vw, 16px);
background: linear-gradient(180deg, #ffffff 0%, #f8f9fa 100%);
position: relative;
">
<div style="
color: #606770;
font-size: clamp(10px, 2.5vw, 11px);
text-transform: uppercase;
margin-bottom: 8px;
word-break: break-all;
font-weight: 600;
letter-spacing: 0.5px;
">
πŸ“˜ {html.escape(display_url)}
</div>
<div style="
color: #1d2129;
font-size: clamp(15px, 4vw, 18px);
font-weight: 700;
line-height: 1.2;
margin-bottom: 8px;
word-break: break-word;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
">
{html.escape(title[:95] + "..." if len(title) > 95 else title)}
</div>
<div style="
color: #65676b;
font-size: clamp(13px, 3.2vw, 15px);
line-height: 1.4;
word-break: break-word;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
">
{html.escape(description[:140] + "..." if len(description) > 140 else description)}
</div>
<div style="
position: absolute;
bottom: 8px;
right: 12px;
font-size: 10px;
color: #8a8d91;
opacity: 0.7;
">
Facebook Preview
</div>
</div>
</div>
"""
return preview_html
def generate_twitter_preview(self, url):
"""Generate Twitter card preview"""
card_type = self.metadata.get('twitter:card', 'summary')
title = self.metadata.get('twitter:title') or self.metadata.get('og:title') or self.metadata.get('title', 'Untitled Page')
description = self.metadata.get('twitter:description') or self.metadata.get('og:description') or self.metadata.get('description', 'No description available.')
image = self.metadata.get('twitter:image') or self.metadata.get('og:image', '')
# Parse URL for display
parsed_url = urlparse(url)
display_url = parsed_url.netloc
preview_html = f"""
<div class="preview-card" style="
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
max-width: 100%;
width: 100%;
border: 1px solid #e1e8ed;
border-radius: 16px;
overflow: hidden;
background-color: #ffffff;
margin: 10px 0;
box-sizing: border-box;
">
"""
# Enhanced image section for Twitter
if image and card_type in ['summary_large_image', 'summary']:
image_height = "clamp(200px, 35vw, 250px)" if card_type == "summary_large_image" else "clamp(120px, 25vw, 150px)"
preview_html += f"""
<div style="
width: 100%;
height: {image_height};
background: linear-gradient(135deg, #1DA1F2 0%, #0d8bd9 50%, #657786 100%);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: white;
font-size: clamp(12px, 3vw, 14px);
position: relative;
overflow: hidden;
">
<div style="
background: rgba(255,255,255,0.15);
border-radius: 15px;
padding: clamp(0.75rem, 3vw, 1.2rem);
text-align: center;
backdrop-filter: blur(10px);
border: 1px solid rgba(255,255,255,0.3);
max-width: 85%;
box-shadow: 0 4px 20px rgba(0,0,0,0.1);
">
<div style="font-size: clamp(1.5rem, 5vw, 2rem); margin-bottom: 0.5rem;">🐦</div>
<div style="font-weight: 600; word-break: break-all; font-size: clamp(11px, 2.8vw, 13px);">
{html.escape(image[:60] + "..." if len(image) > 60 else image)}
</div>
</div>
<div style="
position: absolute;
top: 10px;
right: 15px;
background: rgba(255,255,255,0.2);
border-radius: 20px;
padding: 4px 8px;
font-size: 10px;
font-weight: 500;
">
{card_type.replace('_', ' ').title()}
</div>
</div>
"""
else:
preview_html += f"""
<div style="
width: 100%;
height: clamp(100px, 20vw, 130px);
background: linear-gradient(135deg, #f7f9fa 0%, #e1e8ed 100%);
display: flex;
align-items: center;
justify-content: center;
color: #657786;
font-size: clamp(12px, 3vw, 14px);
border-bottom: 1px solid #e1e8ed;
">
<div style="text-align: center; opacity: 0.6;">
<div style="font-size: clamp(1.5rem, 4vw, 2rem); margin-bottom: 0.5rem;">🐦</div>
<div>No image available</div>
</div>
</div>
"""
# Enhanced content section for Twitter
preview_html += f"""
<div style="
padding: clamp(12px, 3.5vw, 18px);
background: linear-gradient(180deg, #ffffff 0%, #f7f9fa 100%);
position: relative;
border-top: 1px solid #e1e8ed;
">
<div style="
color: #657786;
font-size: clamp(12px, 3vw, 14px);
margin-bottom: 6px;
word-break: break-all;
font-weight: 500;
display: flex;
align-items: center;
gap: 6px;
">
<span style="font-size: 12px;">πŸ”—</span>
{html.escape(display_url)}
</div>
<div style="
color: #0f1419;
font-size: clamp(15px, 4vw, 17px);
font-weight: 700;
line-height: 1.25;
margin-bottom: 8px;
word-break: break-word;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
">
{html.escape(title[:75] + "..." if len(title) > 75 else title)}
</div>
<div style="
color: #536471;
font-size: clamp(14px, 3.2vw, 15px);
line-height: 1.4;
word-break: break-word;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
margin-bottom: 8px;
">
{html.escape(description[:130] + "..." if len(description) > 130 else description)}
</div>
<div style="
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 12px;
padding-top: 8px;
border-top: 1px solid #eff3f4;
">
<div style="
font-size: 10px;
color: #8b98a5;
opacity: 0.8;
">
Twitter Card Preview
</div>
<div style="
display: flex;
gap: 12px;
opacity: 0.6;
">
<span style="font-size: 14px;">πŸ’¬</span>
<span style="font-size: 14px;">πŸ”„</span>
<span style="font-size: 14px;">❀️</span>
<span style="font-size: 14px;">πŸ“€</span>
</div>
</div>
</div>
</div>
"""
return preview_html