Compare commits
10 commits
d75cc3e904
...
273200f8a4
Author | SHA1 | Date | |
---|---|---|---|
273200f8a4 | |||
e3aaba8483 | |||
a6ec889b11 | |||
92c40adcd7 | |||
83c23ffe69 | |||
0b8fae74e4 | |||
5ed3568436 | |||
e453127ddb | |||
f5a3021d81 | |||
fbe512d549 |
5 changed files with 134 additions and 91 deletions
|
@ -48,6 +48,8 @@ Customize the templates (if you know HTML, CSS and Jinja2) and run the command.
|
||||||
-P, --mail-pass TEXT User password for SMTP Mail server to send
|
-P, --mail-pass TEXT User password for SMTP Mail server to send
|
||||||
emails.
|
emails.
|
||||||
-p, --mail-server-port INTEGER SMTP Mail server port to send emails.
|
-p, --mail-server-port INTEGER SMTP Mail server port to send emails.
|
||||||
|
-t, --subjet-template TEXT Jinja2 template for the subject of the
|
||||||
|
emails.
|
||||||
-l, --log-file TEXT File to store all debug messages.
|
-l, --log-file TEXT File to store all debug messages.
|
||||||
--config FILE Read configuration from FILE.
|
--config FILE Read configuration from FILE.
|
||||||
--help Show this message and exit.
|
--help Show this message and exit.
|
||||||
|
|
|
@ -18,7 +18,8 @@ import sqlite3
|
||||||
import click
|
import click
|
||||||
import click_config_file
|
import click_config_file
|
||||||
import requests
|
import requests
|
||||||
from jinja2 import Environment, PackageLoader, select_autoescape, FileSystemLoader
|
from jinja2 import Environment, select_autoescape, FileSystemLoader
|
||||||
|
import importlib
|
||||||
|
|
||||||
class MastodonEmailBridge:
|
class MastodonEmailBridge:
|
||||||
'''CLass to redirect the Mastodon home timeline to email'''
|
'''CLass to redirect the Mastodon home timeline to email'''
|
||||||
|
@ -170,19 +171,19 @@ class MastodonEmailBridge:
|
||||||
sender = self._str_template(self.config['sender'], data)
|
sender = self._str_template(self.config['sender'], data)
|
||||||
recipient = self._str_template(self.config['recipient'], data)
|
recipient = self._str_template(self.config['recipient'], data)
|
||||||
msg = MIMEMultipart('alternative')
|
msg = MIMEMultipart('alternative')
|
||||||
if data['in_reply_to_id']:
|
msg['Subject'] = self._str_template(self.config['subjet_template'], data)
|
||||||
msg['Subject'] = f"FediReply from {data['account']['display_name']} ({data['account']['username']})"
|
|
||||||
else:
|
|
||||||
msg['Subject'] = f"FediPost from {data['account']['display_name']} ({data['account']['username']})"
|
|
||||||
msg['From'] = sender
|
msg['From'] = sender
|
||||||
|
msg['Date'] = time.strftime('%a, %d %b %Y %H:%M:%S %z')
|
||||||
msg['To'] = recipient
|
msg['To'] = recipient
|
||||||
html_template = self.j2env.get_template("new_post.html.j2")
|
html_template = self.j2env.get_template("new_post.html.j2")
|
||||||
html_source = html_template.render(
|
html_source = html_template.render(
|
||||||
|
imp0rt = importlib.import_module,
|
||||||
data=data,
|
data=data,
|
||||||
json_raw=json.dumps(data, indent=2)
|
json_raw=json.dumps(data, indent=2)
|
||||||
)
|
)
|
||||||
txt_template = self.j2env.get_template("new_post.txt.j2")
|
txt_template = self.j2env.get_template("new_post.txt.j2")
|
||||||
txt_source = txt_template.render(
|
txt_source = txt_template.render(
|
||||||
|
imp0rt = importlib.import_module,
|
||||||
data=data,
|
data=data,
|
||||||
json_raw=json.dumps(data, indent=2)
|
json_raw=json.dumps(data, indent=2)
|
||||||
)
|
)
|
||||||
|
@ -321,6 +322,12 @@ class MastodonEmailBridge:
|
||||||
default=465,
|
default=465,
|
||||||
help='SMTP Mail server port to send emails.'
|
help='SMTP Mail server port to send emails.'
|
||||||
)
|
)
|
||||||
|
@click.option(
|
||||||
|
'--subjet-template',
|
||||||
|
'-t',
|
||||||
|
default='{{ data["account"]["display_name"] }} ({{ data["account"]["username"] }}) {% if data["in_reply_to_id"] %}replied {% else %}posted{% endif %}{% for tag in data["tags"] %} #{{ tag["name"] }}{% endfor %}',
|
||||||
|
help='Jinja2 template for the subject of the emails.'
|
||||||
|
)
|
||||||
@click.option('--log-file', '-l', help="File to store all debug messages.")
|
@click.option('--log-file', '-l', help="File to store all debug messages.")
|
||||||
# @click.option("--dummy","-n", is_flag=True,
|
# @click.option("--dummy","-n", is_flag=True,
|
||||||
# help="Don't do anything, just show what would be done.")
|
# help="Don't do anything, just show what would be done.")
|
||||||
|
|
|
@ -7,7 +7,7 @@ Homepage = "https://codeberg.org/adelgado/mastodon_email_bridge"
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "mastodon_email_bridge"
|
name = "mastodon_email_bridge"
|
||||||
version = "0.0.6"
|
version = "1.0.0"
|
||||||
description = "Redirect your Mastodon Home timeline to your email"
|
description = "Redirect your Mastodon Home timeline to your email"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
authors = [{ name = "Antonio J. Delgado", email = "ad@susurrando.com" }]
|
authors = [{ name = "Antonio J. Delgado", email = "ad@susurrando.com" }]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[metadata]
|
[metadata]
|
||||||
name = mastodon_email_bridge
|
name = mastodon_email_bridge
|
||||||
version = 0.0.6
|
version = 1.0.0
|
||||||
|
|
||||||
[options]
|
[options]
|
||||||
packages = mastodon_email_bridge
|
packages = mastodon_email_bridge
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
{% set time = imp0rt( 'time' ) %}
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="{{ data['language'] }}">
|
<html lang="{{ data['language'] }}">
|
||||||
<head>
|
<head>
|
||||||
|
@ -6,7 +7,10 @@
|
||||||
<style>
|
<style>
|
||||||
body { background-color: black; color: #999;}
|
body { background-color: black; color: #999;}
|
||||||
p { }
|
p { }
|
||||||
div { margin: 1%; }
|
div {
|
||||||
|
margin: 1%;
|
||||||
|
{# border-style: dashed; #}
|
||||||
|
}
|
||||||
/* unvisited link */
|
/* unvisited link */
|
||||||
a:link {
|
a:link {
|
||||||
color: blueviolet;
|
color: blueviolet;
|
||||||
|
@ -27,114 +31,143 @@
|
||||||
<BODY>
|
<BODY>
|
||||||
{% if data['url'] != "" %}
|
{% if data['url'] != "" %}
|
||||||
<!-- URL -->
|
<!-- URL -->
|
||||||
<DIV>
|
<A TARGET="_blank" HREF="{{ data['url'] }}">Post original page</A>
|
||||||
<A TARGET="_blank" HREF="{{ data['url'] }}">Post original page</A>
|
|
||||||
</DIV>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<!-- creation_date -->
|
||||||
|
<P STYLE='font-size: 12px;'>
|
||||||
|
{% set created_date = time.strptime(data['created_at'], '%Y-%m-%dT%H:%M:%S.%fZ') %}
|
||||||
|
{{ time.strftime('%Y-%m-%d %H:%M:%S %zUTC', created_date) }}
|
||||||
|
</P>
|
||||||
|
|
||||||
<!-- account bloc -->
|
<!-- account bloc -->
|
||||||
<DIV>
|
<TABLE>
|
||||||
<A HREF="{{ data['account']['url'] }}" TARGET="_blank"></A>
|
<TR>
|
||||||
<IMG ALT="{{ data['account']['display_name'] }} avatar image" SRC="{{ data['account']['avatar_static'] }}" STYLE="width:64px;height:64px;margin:1%;float: left;">
|
<TD>
|
||||||
<B>{{ data['account']['display_name'] }} ({{ data['account']['username'] }})</B>
|
<A HREF="{{ data['account']['url'] }}" TARGET="_blank">
|
||||||
</A>
|
<IMG ALT="{{ data['account']['display_name'] }} avatar image" SRC="{{ data['account']['avatar_static'] }}" STYLE="width:64px;height:64px;margin:1%;float: left;">
|
||||||
</DIV>
|
</A>
|
||||||
<!-- creation_date -->
|
</TD>
|
||||||
<DIV STYLE='font-size: 0.75em;'>
|
<TD>
|
||||||
{{ data['created_at'] }}
|
<A HREF="{{ data['account']['url'] }}" TARGET="_blank">
|
||||||
</DIV>
|
<B>{{ data['account']['display_name'] }} ({{ data['account']['acct'] }})</B>
|
||||||
|
</A>
|
||||||
|
</TD>
|
||||||
|
</TR>
|
||||||
|
</TABLE>
|
||||||
<!-- content block -->
|
<!-- content block -->
|
||||||
<DIV STYLE='font-size: 1.5em;'>
|
<DIV STYLE='font-size: 24px;'>
|
||||||
|
{% if data['spoiler'] != "" and data['spoiler'] != null %}
|
||||||
<!-- spoiler -->
|
<!-- spoiler -->
|
||||||
<DIV CLASS='item-spoiler'>
|
<DIV CLASS='item-spoiler'>
|
||||||
{{ data['spoiler'] }}
|
{{ data['spoiler'] }}
|
||||||
</DIV>
|
</DIV>
|
||||||
|
{% endif %}
|
||||||
<!-- item-content -->
|
<!-- item-content -->
|
||||||
<DIV CLASS='item-content' STYLE="margin:5%;">
|
<DIV CLASS='item-content' STYLE="margin:0.5%;background-color:#111;padding:0.5%;">
|
||||||
{{ data['content'] }}
|
{{ data['content'] }}
|
||||||
<!-- media -->
|
<!-- media -->
|
||||||
{% if data['media_attachments'] %}
|
{% if data['media_attachments'] %}
|
||||||
{% for media in data['media_attachments'] %}
|
{% for media in data['media_attachments'] %}
|
||||||
<DIV STYLE="margin:2%;">
|
{% if media['type'] == 'image' -%}
|
||||||
{% if media['type'] == 'image' %}
|
|
||||||
<IMG SRC="{{ media['preview_url'] }}" ALT="{{ media['description'] }}">
|
|
||||||
{% elif media['type'] == 'video' or media['type'] == 'gifv' %}
|
|
||||||
<video controls width="100%">
|
|
||||||
<source src="{{ media['url'] }}" type="video/webm" />
|
|
||||||
<A HREF="{{ media['url'] }}">Download video</A>
|
|
||||||
</video>
|
|
||||||
{% elif media['type'] == 'audio' %}
|
|
||||||
<audio controls src="{{ media['url'] }}"></audio>
|
|
||||||
<A HREF="{{ media['url'] }}">Download audio</A>
|
|
||||||
{% endif %}
|
|
||||||
</DIV>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
{% if data['reply'] %}
|
|
||||||
<!-- reply -->
|
|
||||||
<DIV STYLE="margin:5%;">
|
|
||||||
<DIV>
|
|
||||||
<A TARGET="_blank" HREF="{{ data['reply']['url'] }}">Reply original page</A>
|
|
||||||
</DIV>
|
|
||||||
<!-- reply-account -->
|
|
||||||
<DIV>
|
|
||||||
<A HREF="{{ data['reply']['account']['url'] }}" TARGET="_blank"></A>
|
|
||||||
<IMG ALT="{{ data['reply']['account']['display_name'] }} avatar image" SRC="{{ data['reply']['account']['avatar_static'] }}" STYLE='width:64px;height:64px;margin:1%;float: left;'>
|
|
||||||
<B>{{ data['reply']['account']['display_name'] }} ({{ data['reply']['account']['username'] }})</B>
|
|
||||||
</A>
|
|
||||||
</DIV>
|
|
||||||
<!-- reply_creation_date -->
|
|
||||||
<DIV STYLE='font-size: 0.75em;'>
|
|
||||||
{{ data['reply']['created_at'] }}
|
|
||||||
</DIV>
|
|
||||||
<!-- reply_content_bloc -->
|
|
||||||
<DIV STYLE='font-size: 1.5em;'>
|
|
||||||
<!-- reply_spoiler -->
|
|
||||||
<DIV CLASS='reply-spoiler'>
|
|
||||||
{{ data['reply']['spoiler'] }}
|
|
||||||
</DIV>
|
|
||||||
<!-- reply_content -->
|
|
||||||
<DIV CLASS='reply-content'>
|
|
||||||
{{ data['reply']['content'] }}
|
|
||||||
<!-- media -->
|
|
||||||
{% if data['reply']['media_attachments'] %}
|
|
||||||
{% for media in data['reply']['media_attachments'] %}
|
|
||||||
{% if media['type'] == 'image' %}
|
|
||||||
<IMG SRC="{{ media['preview_url'] }}" ALT="{{ media['description'] }}">
|
<IMG SRC="{{ media['preview_url'] }}" ALT="{{ media['description'] }}">
|
||||||
{% elif media['type'] == 'video' %}
|
{% elif media['type'] == 'video' or media['type'] == 'gifv' -%}
|
||||||
<video controls width="100%">
|
<video controls height="50%">
|
||||||
<source src="{{ media['url'] }}" type="video/webm" />
|
<source src="{{ media['url'] }}" type="video/webm" />
|
||||||
<A HREF="{{ media['url'] }}">Download video</A>
|
<A HREF="{{ media['url'] }}">Download video</A>
|
||||||
</video>
|
</video>
|
||||||
{% elif media['type'] == 'audio' %}
|
{% elif media['type'] == 'audio' -%}
|
||||||
<audio controls src="{{ media['url'] }}"></audio>
|
<audio controls src="{{ media['url'] }}"></audio>
|
||||||
<A HREF="{{ media['url'] }}">Download audio</A>
|
<A HREF="{{ media['url'] }}">Download audio</A>
|
||||||
{% endif %}
|
{% else %}
|
||||||
{% endfor %}
|
<object data="{{ media['url'] }}"></object>
|
||||||
|
{%- endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% if data['meb_reply_to'] %}
|
||||||
|
{% for reply in data['meb_reply_to'] %}
|
||||||
|
<!-- reply -->
|
||||||
|
<A TARGET="_blank" HREF="{{ reply['url'] }}">Reply original page</A>
|
||||||
|
<!-- creation_date -->
|
||||||
|
<P STYLE='font-size: 12px;'>
|
||||||
|
{% set reply_created_date = time.strptime(reply['created_at'], '%Y-%m-%dT%H:%M:%S.%fZ') %}
|
||||||
|
{{ time.strftime('%Y-%m-%d %H:%M:%S %zUTC', reply_created_date) }}
|
||||||
|
</P>
|
||||||
|
|
||||||
|
<DIV STYLE="margin:1%;">
|
||||||
|
<!-- reply-account -->
|
||||||
|
<TABLE>
|
||||||
|
<TR>
|
||||||
|
<TD>
|
||||||
|
<A HREF="{{ reply['account']['url'] }}" TARGET="_blank">
|
||||||
|
<IMG ALT="{{ reply['account']['display_name'] }} avatar image" SRC="{{ reply['account']['avatar_static'] }}" STYLE="width:64px;height:64px;margin:1%;float: left;">
|
||||||
|
</A>
|
||||||
|
</TD>
|
||||||
|
<TD>
|
||||||
|
<A HREF="{{ reply['account']['url'] }}" TARGET="_blank">
|
||||||
|
<B>{{ reply['account']['display_name'] }} ({{ reply['account']['acct'] }})</B>
|
||||||
|
</A>
|
||||||
|
</TD>
|
||||||
|
</TR>
|
||||||
|
</TABLE>
|
||||||
|
<!-- reply_content_bloc -->
|
||||||
|
<DIV STYLE='font-size: 24px;'>
|
||||||
|
<!-- reply_spoiler -->
|
||||||
|
<DIV CLASS='reply-spoiler'>
|
||||||
|
{{ reply['spoiler'] }}
|
||||||
|
</DIV>
|
||||||
|
<!-- reply_content -->
|
||||||
|
<DIV CLASS='reply-content'>
|
||||||
|
{{ reply['content'] }}
|
||||||
|
<!-- media -->
|
||||||
|
{% if reply['media_attachments'] %}
|
||||||
|
{% for media in reply['media_attachments'] %}
|
||||||
|
{% if media['type'] == 'image' %}
|
||||||
|
<IMG SRC="{{ media['preview_url'] }}" ALT="{{ media['description'] }}">
|
||||||
|
{% elif media['type'] == 'video' %}
|
||||||
|
<video controls width="100%">
|
||||||
|
<source src="{{ media['url'] }}" type="video/webm" />
|
||||||
|
<A HREF="{{ media['url'] }}">Download video</A>
|
||||||
|
</video>
|
||||||
|
{% elif media['type'] == 'audio' %}
|
||||||
|
<audio controls src="{{ media['url'] }}"></audio>
|
||||||
|
<A HREF="{{ media['url'] }}">Download audio</A>
|
||||||
|
{% else %}
|
||||||
|
<object data="{{ media['url'] }}"></object>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</DIV>
|
</DIV>
|
||||||
</DIV>
|
</DIV>
|
||||||
</DIV>
|
</DIV>
|
||||||
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if data['reblog'] %}
|
{% if data['reblog'] %}
|
||||||
<!-- reblog -->
|
<!-- reblog -->
|
||||||
<DIV STYLE="margin:5%;">
|
<DIV STYLE="margin:1%;">
|
||||||
<DIV>
|
<!-- reply -->
|
||||||
<A TARGET="_blank" HREF="{{ data['reblog']['url'] }}">Reply original page</A>
|
<A TARGET="_blank" HREF="{{ data['reblog']['url'] }}">Reply original page</A>
|
||||||
</DIV>
|
<!-- creation_date -->
|
||||||
|
<P STYLE='font-size: 12px;'>
|
||||||
|
{% set reblog_created_date = time.strptime(data['reblog']['created_at'], '%Y-%m-%dT%H:%M:%S.%fZ') %}
|
||||||
|
{{ time.strftime('%Y-%m-%d %H:%M:%S %zUTC', reblog_created_date) }}
|
||||||
|
</P>
|
||||||
<!-- reblog-account -->
|
<!-- reblog-account -->
|
||||||
<DIV>
|
<TABLE>
|
||||||
<A HREF="{{ data['reblog']['account']['url'] }}" TARGET="_blank"></A>
|
<TR>
|
||||||
<IMG ALT="{{ data['reblog']['account']['display_name'] }} avatar image" SRC="{{ data['reblog']['account']['avatar_static'] }}" STYLE='width:64px;height:64px;margin:1%;float: left;'>
|
<TD>
|
||||||
<B>{{ data['reblog']['account']['display_name'] }} ({{ data['reblog']['account']['username'] }})</B>
|
<A HREF="{{ data['reblog']['account']['url'] }}" TARGET="_blank">
|
||||||
</A>
|
<IMG ALT="{{ data['reblog']['account']['display_name'] }} avatar image" SRC="{{ data['reblog']['account']['avatar_static'] }}" STYLE="width:64px;height:64px;margin:1%;float: left;">
|
||||||
</DIV>
|
</A>
|
||||||
<!-- reblog_creation_date -->
|
</TD>
|
||||||
<DIV STYLE='font-size: 0.75em;'>
|
<TD>
|
||||||
{{ data['reblog']['created_at'] }}
|
<A HREF="{{ data['reblog']['account']['url'] }}" TARGET="_blank">
|
||||||
</DIV>
|
<B>{{ data['reblog']['account']['display_name'] }} ({{ data['reblog']['account']['acct'] }})</B>
|
||||||
|
</A>
|
||||||
|
</TD>
|
||||||
|
</TR>
|
||||||
|
</TABLE>
|
||||||
<!-- reblog_content_bloc -->
|
<!-- reblog_content_bloc -->
|
||||||
<DIV STYLE='font-size: 1.5em;'>
|
<DIV STYLE='font-size: 24px;'>
|
||||||
<!-- reblog_spoiler -->
|
<!-- reblog_spoiler -->
|
||||||
<DIV CLASS='reblog-spoiler'>
|
<DIV CLASS='reblog-spoiler'>
|
||||||
{{ data['reblog']['spoiler'] }}
|
{{ data['reblog']['spoiler'] }}
|
||||||
|
@ -165,9 +198,10 @@
|
||||||
</DIV>
|
</DIV>
|
||||||
</DIV>
|
</DIV>
|
||||||
{# <!-- card -->{{ data['card'] }} #}
|
{# <!-- card -->{{ data['card'] }} #}
|
||||||
<!-- Raw JSON data -->
|
<!-- Raw JSON data
|
||||||
<DIV STYLE="margin-top:15%;font-size:0.75em;">
|
<DIV STYLE="margin-top:15%;font-size: 12px;">
|
||||||
Raw JSON data:
|
Raw JSON data:
|
||||||
<PRE>{{ json_raw }}</PRE>
|
<PRE>{{ json_raw }}</PRE>
|
||||||
</DIV>
|
</DIV>
|
||||||
|
-->
|
||||||
</BODY>
|
</BODY>
|
||||||
|
|
Loading…
Reference in a new issue