From bab4d1009c81dc5e5be39a56eda4bd79cac07012 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Joakim=20Hells=C3=A9n?= <tlovinator@gmail.com>
Date: Sat, 21 Jan 2023 14:16:08 +0100
Subject: [PATCH] Add button to send entry to Discord

---
 discord_rss_bot/custom_message.py     |  11 ++-
 discord_rss_bot/feeds.py              |  47 +++++++++++
 discord_rss_bot/main.py               |  55 ++++++++----
 discord_rss_bot/templates/custom.html | 117 +++++++++++++-------------
 4 files changed, 153 insertions(+), 77 deletions(-)

diff --git a/discord_rss_bot/custom_message.py b/discord_rss_bot/custom_message.py
index 6547981..bc4134f 100644
--- a/discord_rss_bot/custom_message.py
+++ b/discord_rss_bot/custom_message.py
@@ -75,11 +75,13 @@ def replace_tags(feed: Feed, entry: Entry) -> str:
     content = ""
     if entry.summary:
         summary: str = entry.summary
+        summary = convert_to_md(summary)
         summary = remove_image_tags(message=summary)
 
     if entry.content:
         for content_item in entry.content:
             content: str = content_item.value
+            content = convert_to_md(content)
             content = remove_image_tags(message=content)
 
     if images := get_images_from_entry(entry=entry):
@@ -103,7 +105,7 @@ def replace_tags(feed: Feed, entry: Entry) -> str:
         {"{{entry_added}}": entry.added},
         {"{{entry_author}}": entry.author},
         {"{{entry_content}}": content},
-        {"{{entry_content_raw}}": content},
+        {"{{entry_content_raw}}": entry.content[0].value if entry.content else ""},
         {"{{entry_id}}": entry.id},
         {"{{entry_important}}": str(entry.important)},
         {"{{entry_link}}": entry.link},
@@ -111,7 +113,7 @@ def replace_tags(feed: Feed, entry: Entry) -> str:
         {"{{entry_read}}": str(entry.read)},
         {"{{entry_read_modified}}": entry.read_modified},
         {"{{entry_summary}}": summary},
-        {"{{entry_summary_raw}}": summary},
+        {"{{entry_summary_raw}}": entry.summary if entry.summary else ""},
         {"{{entry_title}}": entry.title},
         {"{{entry_updated}}": entry.updated},
         {"{{image_1}}": first_image},
@@ -121,7 +123,10 @@ def replace_tags(feed: Feed, entry: Entry) -> str:
         for template, replace_with in replacement.items():
             custom_message = try_to_replace(custom_message, template, replace_with)
 
-    return custom_message
+    # Replace \\n with newlines.
+    custom_message_with_newlines = custom_message.replace("\\n", "\n")
+
+    return custom_message_with_newlines
 
 
 def get_custom_message(custom_reader: Reader, feed: Feed) -> str:
diff --git a/discord_rss_bot/feeds.py b/discord_rss_bot/feeds.py
index b4b5316..506cf67 100644
--- a/discord_rss_bot/feeds.py
+++ b/discord_rss_bot/feeds.py
@@ -10,6 +10,53 @@ from discord_rss_bot.filter.whitelist import has_white_tags, should_be_sent
 from discord_rss_bot.settings import default_custom_message, get_reader
 
 
+def get_entry_from_id(entry_id: str, custom_reader: Reader | None = None) -> Entry | None:
+    """
+    Get an entry from an ID.
+
+    Args:
+        entry_id: The ID of the entry.
+        custom_reader: If we should use a custom reader instead of the default one.
+
+    Returns:
+        Entry: The entry with the ID. None if it doesn't exist.
+    """
+    # Get the default reader if we didn't get a custom one.
+    reader: Reader = get_reader() if custom_reader is None else custom_reader
+
+    # Get the entry from the ID, or return None if it doesn't exist.
+    return next((entry for entry in reader.get_entries() if entry.id == entry_id), None)
+
+
+def send_entry_to_discord(entry: Entry, custom_reader: Reader | None = None):
+    """
+    Send a single entry to Discord.
+
+    Args:
+        entry: The entry to send to Discord.
+    """
+    # Get the default reader if we didn't get a custom one.
+    reader: Reader = get_reader() if custom_reader is None else custom_reader
+
+    # Get the webhook URL for the entry.
+    webhook_url: str = settings.get_webhook_for_entry(reader, entry)
+    if not webhook_url:
+        return "No webhook URL found."
+
+    # Try to get the custom message for the feed. If the user has none, we will use the default message.
+    if custom_message.get_custom_message(reader, entry.feed) != "":
+        webhook_message = custom_message.replace_tags(entry=entry, feed=entry.feed)  # type: ignore
+    else:
+        webhook_message: str = default_custom_message
+
+    # Create the webhook.
+    webhook: DiscordWebhook = DiscordWebhook(url=webhook_url, content=webhook_message, rate_limit_retry=True)
+
+    response: Response = webhook.execute()
+    if not response.ok:
+        return f"Error sending entry to Discord: {response.text}"
+
+
 def send_to_discord(custom_reader: Reader | None = None, feed: Feed | None = None, do_once: bool = False) -> None:
     """
     Send entries to Discord.
diff --git a/discord_rss_bot/main.py b/discord_rss_bot/main.py
index fc9067b..9eea81a 100644
--- a/discord_rss_bot/main.py
+++ b/discord_rss_bot/main.py
@@ -14,7 +14,7 @@ from starlette.responses import RedirectResponse
 from discord_rss_bot import settings
 from discord_rss_bot.custom_filters import convert_to_md, encode_url, entry_is_blacklisted, entry_is_whitelisted
 from discord_rss_bot.custom_message import get_custom_message, get_images_from_entry, remove_image_tags
-from discord_rss_bot.feeds import send_to_discord
+from discord_rss_bot.feeds import get_entry_from_id, send_entry_to_discord, send_to_discord
 from discord_rss_bot.filter.blacklist import get_blacklist_content, get_blacklist_summary, get_blacklist_title
 from discord_rss_bot.filter.whitelist import get_whitelist_content, get_whitelist_summary, get_whitelist_title
 from discord_rss_bot.search import create_html_for_search_results
@@ -426,13 +426,14 @@ def create_html_for_feed(entries: Iterable[Entry]) -> str:
     for entry in entries:
 
         # Get first image.
+        first_image = ""
+        first_image_text = ""
         if images := get_images_from_entry(entry=entry):
             first_image: str = images[0][1]
             first_image_text: str = images[0][0]
-        else:
-            first_image = ""
-            first_image_text = ""
 
+        # Get the text from the entry.
+        text = "<div class='text-muted'>No content available.</div>"
         if entry.summary:
             summary: str = convert_to_md(entry.summary)
             summary = remove_image_tags(message=summary)
@@ -441,32 +442,30 @@ def create_html_for_feed(entries: Iterable[Entry]) -> str:
             content: str = convert_to_md(entry.content[0].value)
             content = remove_image_tags(message=content)
             text = f"<div class='text-muted'>{content}</div>"
-        else:
-            text = "<div class='text-muted'>No content available.</div>"
 
+        published = ""
         if entry.published:
             published: str = entry.published.strftime("%Y-%m-%d %H:%M:%S")
-        else:
-            published = ""
 
+        blacklisted = ""
         if entry_is_blacklisted(entry):
             blacklisted = "<span class='badge bg-danger'>Blacklisted</span>"
-        else:
-            blacklisted = ""
 
+        whitelisted = ""
         if entry_is_whitelisted(entry):
             whitelisted = "<span class='badge bg-success'>Whitelisted</span>"
-        else:
-            whitelisted = ""
+
+        entry_id: str = urllib.parse.quote(entry.id)
+        to_disord_html: str = f"<a class='text-muted' href='/post_entry?entry_id={entry_id}'>Send to Discord</a>"
 
         html += f"""
             <div class="p-2 mb-2 border border-dark">
             {blacklisted}
             {whitelisted}
-            <h2>
-                <a class="text-muted text-decoration-none" href="{entry.link}">{entry.title}</a>
-            </h2>
-            {f"By { entry.author } @" if entry.author else ""} {published}
+
+            <a class="text-muted text-decoration-none" href="{entry.link}"><h2>{entry.title}</h2></a>
+
+            {f"By { entry.author } @" if entry.author else ""} {published} - {to_disord_html}
             {text}
             {f"<img src='{first_image}' class='img-fluid' alt='{first_image_text}'>" if first_image else ""}
             </div>
@@ -591,6 +590,30 @@ async def search(request: Request, query: str):
     return templates.TemplateResponse("search.html", context)
 
 
+@app.get("/post_entry", response_class=HTMLResponse)
+async def post_entry(entry_id: str):
+    """
+    Send a feed to Discord.
+
+    Returns:
+        HTMLResponse: The HTML response.
+    """
+    # Unquote the entry id.
+    unquoted_entry_id: str = urllib.parse.unquote(entry_id)
+
+    print(f"Sending entry '{unquoted_entry_id}' to Discord.")
+    entry: Entry | None = get_entry_from_id(entry_id=unquoted_entry_id)
+    if entry is None:
+        return {"error": f"Failed to get entry '{entry_id}' when posting to Discord."}
+
+    if result := send_entry_to_discord(entry=entry):
+        return result
+
+    # Redirect to the feed page.
+    clean_url: str = entry.feed.url.strip()
+    return RedirectResponse(url=f"/feed/?feed_url={clean_url}", status_code=303)
+
+
 @app.on_event("startup")
 def startup() -> None:
     """This is called when the server starts.
diff --git a/discord_rss_bot/templates/custom.html b/discord_rss_bot/templates/custom.html
index 2c5bb38..834b92d 100644
--- a/discord_rss_bot/templates/custom.html
+++ b/discord_rss_bot/templates/custom.html
@@ -11,196 +11,198 @@
                     <div class="form-text">
                         <ul class="list-inline">
                             <li>You can modify the message that is sent to Discord.</li>
+                            <li> You can use \n to create a new line.</li>
+                            <li> You can remove the embed from links by adding < and > around the link. (For example <{% raw %}{{entry_link}}{% endraw %}>)</li>
                             <br/>
                             <li>
                                 <code>
                                     {% raw %}
-                                        {{ feed_author }}
+                                        {{feed_author}}
                                     {% endraw %}
-                                </code>{{ feed.author }}
+                                </code>{{feed.author}}
                             </li>
                             <li>
                                 <code>
                                     {% raw %}
-                                        {{ feed_added }}
+                                        {{feed_added}}
                                     {% endraw %}
-                                </code>{{ feed.added }}
+                                </code>{{feed.added}}
                             </li>
                             <li>
                                 <code>
                                     {% raw %}
-                                        {{ feed_last_exception }}
+                                        {{feed_last_exception}}
                                     {% endraw %}
-                                </code>{{ feed.last_exception }}
+                                </code>{{feed.last_exception}}
                             </li>
                             <li>
                                 <code>
                                     {% raw %}
-                                        {{ feed_last_updated }}
+                                        {{feed_last_updated}}
                                     {% endraw %}
-                                </code>{{ feed.last_updated }}
+                                </code>{{feed.last_updated}}
                             </li>
                             <li>
                                 <code>
                                     {% raw %}
-                                        {{ feed_link }}
+                                        {{feed_link}}
                                     {% endraw %}
-                                </code>{{ feed.link }}
+                                </code>{{feed.link}}
                             </li>
                             <li>
                                 <code>
                                     {% raw %}
-                                        {{ feed_subtitle }}
+                                        {{feed_subtitle}}
                                     {% endraw %}
-                                </code>{{ feed.subtitle }}
+                                </code>{{feed.subtitle}}
                             </li>
                             <li>
                                 <code>
                                     {% raw %}
-                                        {{ feed_title }}
+                                        {{feed_title}}
                                     {% endraw %}
-                                </code>{{ feed.title }}
+                                </code>{{feed.title}}
                             </li>
                             <li>
                                 <code>
                                     {% raw %}
-                                        {{ feed_updated }}
+                                        {{feed_updated}}
                                     {% endraw %}
-                                </code>{{ feed.updated }}
+                                </code>{{feed.updated}}
                             </li>
                             <li>
                                 <code>
                                     {% raw %}
-                                        {{ feed_updates_enabled }}
+                                        {{feed_updates_enabled}}
                                     {% endraw %}
-                                </code>{{ feed.updates_enabled }}
+                                </code>{{feed.updates_enabled}}
                             </li>
                             <li>
                                 <code>
                                     {% raw %}
-                                        {{ feed_url }}
+                                        {{feed_url}}
                                     {% endraw %}
-                                </code>{{ feed.url }}
+                                </code>{{feed.url}}
                             </li>
                             <li>
                                 <code>
                                     {% raw %}
-                                        {{ feed_user_title }}
+                                        {{feed_user_title}}
                                     {% endraw %}
-                                </code>{{ feed.user_title }}
+                                </code>{{feed.user_title}}
                             </li>
                             <li>
                                 <code>
                                     {% raw %}
-                                        {{ feed_version }}
+                                        {{feed_version}}
                                     {% endraw %}
-                                </code>{{ feed.version }}
+                                </code>{{feed.version}}
                             </li>
                             <br/>
                             {% if entry %}
                                 <li>
                                     <code>
                                         {% raw %}
-                                            {{ entry_added }}
+                                            {{entry_added}}
                                         {% endraw %}
-                                    </code>{{ entry.added }}
+                                    </code>{{entry.added}}
                                 </li>
                                 <li>
                                     <code>
                                         {% raw %}
-                                            {{ entry_author }}
+                                            {{entry_author}}
                                         {% endraw %}
-                                    </code>{{ entry.author }}
+                                    </code>{{entry.author}}
                                 </li>
                                 <li>
                                     <code>
                                         {% raw %}
-                                            {{ entry_content }}
+                                            {{entry_content}}
                                         {% endraw %}
-                                    </code>{{ entry.content[0].value|discord_markdown|remove_image_tags }}
+                                    </code>{{entry.content[0].value|discord_markdown|remove_image_tags}}
                                 </li>
                                 <li>
                                     <code>
                                         {% raw %}
-                                            {{ entry_content_raw }}
+                                            {{entry_content_raw}}
                                         {% endraw %}
-                                    </code>{{ entry.content[0].value }}
+                                    </code>{{entry.content[0].value}}
                                 </li>
                                 <li>
                                     <code>
                                         {% raw %}
-                                            {{ entry_id }}
+                                            {{entry_id}}
                                         {% endraw %}
-                                    </code>{{ entry.id }}
+                                    </code>{{entry.id}}
                                 </li>
                                 <li>
                                     <code>
                                         {% raw %}
-                                            {{ entry_important }}
+                                            {{entry_important}}
                                         {% endraw %}
-                                    </code>{{ entry.important }}
+                                    </code>{{entry.important}}
                                 </li>
                                 <li>
                                     <code>
                                         {% raw %}
-                                            {{ entry_link }}
+                                            {{entry_link}}
                                         {% endraw %}
-                                    </code>{{ entry.link }}
+                                    </code>{{entry.link}}
                                 </li>
                                 <li>
                                     <code>
                                         {% raw %}
-                                            {{ entry_published }}
+                                            {{entry_published}}
                                         {% endraw %}
-                                    </code>{{ entry.published }}
+                                    </code>{{entry.published}}
                                 </li>
                                 <li>
                                     <code>
                                         {% raw %}
-                                            {{ entry_read }}
+                                            {{entry_read}}
                                         {% endraw %}
-                                    </code>{{ entry.read }}
+                                    </code>{{entry.read}}
                                 </li>
                                 <li>
                                     <code>
                                         {% raw %}
-                                            {{ entry_read_modified }}
+                                            {{entry_read_modified}}
                                         {% endraw %}
-                                    </code>{{ entry.read_modified }}
+                                    </code>{{entry.read_modified}}
                                 </li>
                                 <li>
                                     <code>
                                         {% raw %}
-                                            {{ entry_summary }}
+                                            {{entry_summary}}
                                         {% endraw %}
-                                    </code>{{ entry.summary|discord_markdown|remove_image_tags }}
+                                    </code>{{entry.summary|discord_markdown|remove_image_tags}}
                                 </li>
                                 <li>
                                     <code>
                                         {% raw %}
-                                            {{ entry_summary_raw }}
+                                            {{entry_summary_raw}}
                                         {% endraw %}
-                                    </code>{{ entry.summary }}
+                                    </code>{{entry.summary}}
                                 </li>
                                 <li>
                                     <code>
                                         {% raw %}
-                                            {{ entry_title }}
+                                            {{entry_title}}
                                         {% endraw %}
-                                    </code>{{ entry.title }}
+                                    </code>{{entry.title}}
                                 </li>
                                 <li>
                                     <code>
                                         {% raw %}
-                                            {{ entry_updated }}
+                                            {{entry_updated}}
                                         {% endraw %}
-                                    </code>{{ entry.updated }}
+                                    </code>{{entry.updated}}
                                 </li>
                                 <br/>
                                 <li>
                                     <code>
                                         {% raw %}
-                                            {{ image_1 }}
+                                            {{image_1}}
                                         {% endraw %}
                                     </code>First image in the entry if it exists
                                 </li>
@@ -210,7 +212,7 @@
                                 <li>
                                     <code>
                                         {% raw %}
-                                            Hello {{ entry_author }}\n{{ feed_title }}\n{{ entry_read }}
+                                            {{feed_title}}\n{{entry_content}}
                                         {% endraw %}
                                     </code>
                                 </li>
@@ -219,9 +221,8 @@
                                 <li>
                                     <code>
                                         <pre>
-Hello {{ entry.author }}
-{{ feed.title }}
-{{ entry.read }}
+{{feed.title -}}
+{{- entry.content[0].value|discord_markdown|remove_image_tags -}}
                             </pre>
                                     </code>
                                 </li>
@@ -241,7 +242,7 @@ Hello {{ entry.author }}
                 </div>
             </div>
             <!-- Add a hidden feed_url field to the form -->
-            <input type="hidden" name="feed_url" value="{{ feed.url }}"/>
+            <input type="hidden" name="feed_url" value="{{feed.url}}"/>
             <!-- Submit button -->
             <div class="d-md-flex">
                 <button class="btn btn-dark btn-sm">Update message</button>