import base64 import html from urllib.parse import urlencode from .recap_email import document def description(entry): if entry['type'] == 'movie': return f"Movie · {entry['year']}" if entry.get('year') else 'Movie' seasons = sorted({item['season'] for item in entry['items'] if isinstance(item.get('season'), int)}) count = len(entry['items']) labels = ', '.join('Specials' if value == 0 else str(value) for value in seasons[:8]) suffix = f" · {'Season' if len(seasons) == 1 else 'Seasons'} {labels}" if labels else '' return f"{count} new {'episode' if count == 1 else 'episodes'}{suffix}" def render_confirmation(username, url): intro = f"Hi {username}, confirm your email to receive new arrivals, featured picks and announcements from Grizzlyflix." return {'subject': 'Confirm your Grizzlyflix newsletter subscription', 'body_text': f'{intro}\n\nConfirm newsletter subscription: {url}\n\nThis link expires in 24 hours. If you did not request this, ignore this email.', 'body_html': document(title='Your next watch starts here.', intro=intro, content='

A weekly look at new movies and TV updates, with posters and links to watch.

', action='Confirm newsletter subscription', url=url, kicker='NEW ON GRIZZLYFLIX', footer='This link expires in 24 hours. If you did not request this, ignore this email.')} def render(content, images, public_url, playback_url, unsubscribe_url, *, preview=False, test=False): esc = html.escape titles = [entry for entry in content['titles'] if entry['selected']] body, lines, attachments = [], [], [] intro = str(content.get('intro') or '').strip() if intro: body.append(f'

{esc(intro).replace(chr(10), "
")}

') lines += [intro, ''] sections = [('Featured picks', [entry for entry in titles if entry['featured']]), ('New movies', [entry for entry in titles if not entry['featured'] and entry['type'] == 'movie']), ('Fresh episodes', [entry for entry in titles if not entry['featured'] and entry['type'] == 'series'])] for heading, entries in sections: if not entries: continue body.append(f'

{heading}

') lines += [heading, ''] for entry in entries: watch = playback_url + '/web/index.html#!/details?' + urlencode({'id': entry['id'], 'serverId': content['server_id']}) image_data = images.get(entry['id']) cid = f"newsletter-{entry['id']}@magent" if image_data: source = 'data:image/jpeg;base64,' + base64.b64encode(image_data).decode() if preview else 'cid:' + cid poster = f'{esc(entry[' if not preview: attachments.append({'cid': cid, 'data': image_data}) else: poster = f'
{"TV" if entry["type"] == "series" else "MOVIE"}
' details = description(entry) overview = str(entry.get('overview') or '')[:180] copy = f'

{esc(overview)}

' if overview and entry['featured'] else '' body.append(f'''
{poster}

{esc(entry['title'])}

{esc(details)}

{copy} Watch on Grizzlyflix ↗
''') lines += [entry['title'], details, watch, ''] if not titles: body.append('

Your next discovery is waiting in Grizzlyflix.

') period = f"{content['period_start'][:10]} to {content['period_end'][:10]} · UTC" footer = f'You subscribed to the Grizzlyflix newsletter.
Arrivals recorded by Jellyfin · {esc(period)}
Unsubscribe from newsletters · Email preferences' subject = ('[Test] ' if test else '') + content['subject'] return {'subject': subject, 'body_text': '\n'.join([subject, '', *lines, f'Browse Grizzlyflix: {playback_url}', '', f'Arrivals recorded by Jellyfin: {period}', f'Unsubscribe from newsletters: {unsubscribe_url}', f'Email preferences: {public_url}/profile#newsletters']), 'body_html': document(title='What’s new on Grizzlyflix', intro=('This is your test edition. ' if test else '') + 'New stories for your watchlist. Find your next movie or catch up on fresh episodes.', content=''.join(body), action='Explore Grizzlyflix', url=playback_url, footer=footer, kicker='YOUR NEXT WATCH'), 'inline_images': attachments}