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>