Add support for webhook embeds
This commit is contained in:
@ -1,3 +1,6 @@
|
||||
import json
|
||||
from dataclasses import dataclass
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
from reader import Entry, Feed, Reader, TagNotFoundError
|
||||
|
||||
@ -5,6 +8,20 @@ from discord_rss_bot.markdown import convert_html_to_md
|
||||
from discord_rss_bot.settings import get_reader
|
||||
|
||||
|
||||
@dataclass()
|
||||
class CustomEmbed:
|
||||
title: str
|
||||
description: str
|
||||
color: str
|
||||
author_name: str
|
||||
author_url: str
|
||||
author_icon_url: str
|
||||
image_url: str
|
||||
thumbnail_url: str
|
||||
footer_text: str
|
||||
footer_icon_url: str
|
||||
|
||||
|
||||
def get_images_from_entry(entry: Entry):
|
||||
"""Get images from a entry.
|
||||
|
||||
@ -16,7 +33,7 @@ def get_images_from_entry(entry: Entry):
|
||||
"""
|
||||
|
||||
def return_image(found_images):
|
||||
soup: BeautifulSoup = BeautifulSoup(found_images, "html.parser")
|
||||
soup: BeautifulSoup = BeautifulSoup(found_images, features="lxml")
|
||||
images = soup.find_all("img")
|
||||
for image in images:
|
||||
image_src = image["src"] or ""
|
||||
@ -43,9 +60,8 @@ def try_to_replace(custom_message: str, template: str, replace_with: str) -> str
|
||||
|
||||
Args:
|
||||
custom_message: The custom_message to replace tags in.
|
||||
feed: The feed to get the tags from.
|
||||
entry: The entry to get the tags from.
|
||||
tag: The tag to replace.
|
||||
template: The tag to replace.
|
||||
replace_with: What to replace the tag with.
|
||||
|
||||
Returns:
|
||||
Returns the custom_message with the tag replaced.
|
||||
@ -56,7 +72,7 @@ def try_to_replace(custom_message: str, template: str, replace_with: str) -> str
|
||||
return custom_message
|
||||
|
||||
|
||||
def replace_tags(feed: Feed, entry: Entry) -> str:
|
||||
def replace_tags_in_text_message(feed: Feed, entry: Entry) -> str:
|
||||
"""Replace tags in custom_message.
|
||||
|
||||
Args:
|
||||
@ -122,6 +138,82 @@ def replace_tags(feed: Feed, entry: Entry) -> str:
|
||||
return custom_message.replace("\\n", "\n")
|
||||
|
||||
|
||||
def replace_tags_in_embed(feed: Feed, entry: Entry) -> CustomEmbed:
|
||||
"""Replace tags in embed.
|
||||
|
||||
Args:
|
||||
feed: The feed to get the tags from.
|
||||
entry: The entry to get the tags from.
|
||||
|
||||
Returns:
|
||||
Returns the embed with the tags replaced.
|
||||
"""
|
||||
|
||||
custom_reader: Reader = get_reader()
|
||||
embed: CustomEmbed = get_embed(feed=feed, custom_reader=custom_reader)
|
||||
|
||||
summary = ""
|
||||
content = ""
|
||||
if entry.summary:
|
||||
summary: str = entry.summary
|
||||
summary = convert_html_to_md(summary)
|
||||
|
||||
if entry.content:
|
||||
for content_item in entry.content:
|
||||
content: str = content_item.value
|
||||
content = convert_html_to_md(content)
|
||||
|
||||
if images := get_images_from_entry(entry=entry):
|
||||
first_image: str = images[0][0]
|
||||
else:
|
||||
first_image = ""
|
||||
|
||||
list_of_replacements = [
|
||||
{"{{feed_author}}": feed.author},
|
||||
{"{{feed_added}}": feed.added},
|
||||
{"{{feed_last_exception}}": feed.last_exception},
|
||||
{"{{feed_last_updated}}": feed.last_updated},
|
||||
{"{{feed_link}}": feed.link},
|
||||
{"{{feed_subtitle}}": feed.subtitle},
|
||||
{"{{feed_title}}": feed.title},
|
||||
{"{{feed_updated}}": feed.updated},
|
||||
{"{{feed_updates_enabled}}": str(feed.updates_enabled)},
|
||||
{"{{feed_url}}": feed.url},
|
||||
{"{{feed_user_title}}": feed.user_title},
|
||||
{"{{feed_version}}": feed.version},
|
||||
{"{{entry_added}}": entry.added},
|
||||
{"{{entry_author}}": entry.author},
|
||||
{"{{entry_content}}": 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},
|
||||
{"{{entry_published}}": entry.published},
|
||||
{"{{entry_read}}": str(entry.read)},
|
||||
{"{{entry_read_modified}}": entry.read_modified},
|
||||
{"{{entry_summary}}": summary},
|
||||
{"{{entry_summary_raw}}": entry.summary or ""},
|
||||
{"{{entry_title}}": entry.title},
|
||||
{"{{entry_updated}}": entry.updated},
|
||||
{"{{image_1}}": first_image},
|
||||
]
|
||||
|
||||
for replacement in list_of_replacements:
|
||||
for template, replace_with in replacement.items():
|
||||
embed.title = try_to_replace(embed.title, template, replace_with)
|
||||
embed.description = try_to_replace(embed.description, template, replace_with)
|
||||
embed.color = try_to_replace(embed.color, template, replace_with)
|
||||
embed.author_name = try_to_replace(embed.author_name, template, replace_with)
|
||||
embed.author_url = try_to_replace(embed.author_url, template, replace_with)
|
||||
embed.author_icon_url = try_to_replace(embed.author_icon_url, template, replace_with)
|
||||
embed.image_url = try_to_replace(embed.image_url, template, replace_with)
|
||||
embed.thumbnail_url = try_to_replace(embed.thumbnail_url, template, replace_with)
|
||||
embed.footer_text = try_to_replace(embed.footer_text, template, replace_with)
|
||||
embed.footer_icon_url = try_to_replace(embed.footer_icon_url, template, replace_with)
|
||||
|
||||
return embed
|
||||
|
||||
|
||||
def get_custom_message(custom_reader: Reader, feed: Feed) -> str:
|
||||
"""Get custom_message tag from feed.
|
||||
|
||||
@ -140,3 +232,102 @@ def get_custom_message(custom_reader: Reader, feed: Feed) -> str:
|
||||
custom_message = ""
|
||||
|
||||
return custom_message
|
||||
|
||||
|
||||
def save_embed(custom_reader: Reader, feed: Feed, embed: CustomEmbed) -> None:
|
||||
"""Set embed tag in feed.
|
||||
|
||||
Args:
|
||||
custom_reader: What Reader to use.
|
||||
feed: The feed to set the tag in.
|
||||
embed: The embed to set.
|
||||
"""
|
||||
embed_dict: dict[str, str] = {
|
||||
"title": embed.title,
|
||||
"description": embed.description,
|
||||
"color": embed.color.replace("#", "").replace("0x", ""),
|
||||
"author_name": embed.author_name,
|
||||
"author_url": embed.author_url,
|
||||
"author_icon_url": embed.author_icon_url,
|
||||
"image_url": embed.image_url,
|
||||
"thumbnail_url": embed.thumbnail_url,
|
||||
"footer_text": embed.footer_text,
|
||||
"footer_icon_url": embed.footer_icon_url,
|
||||
}
|
||||
|
||||
custom_reader.set_tag(feed, "embed", json.dumps(embed_dict)) # type: ignore
|
||||
|
||||
|
||||
def get_embed(custom_reader: Reader, feed: Feed) -> CustomEmbed:
|
||||
"""Get embed tag from feed.
|
||||
|
||||
Args:
|
||||
custom_reader: What Reader to use.
|
||||
feed: The feed to get the tag from.
|
||||
|
||||
Returns:
|
||||
Returns the contents from the embed tag.
|
||||
"""
|
||||
embed_json: dict[str, str] = {}
|
||||
try:
|
||||
embed: str = str(custom_reader.get_tag(feed, "embed"))
|
||||
except TagNotFoundError:
|
||||
embed = ""
|
||||
except ValueError:
|
||||
embed = ""
|
||||
|
||||
if embed:
|
||||
try:
|
||||
embed_json = json.loads(embed)
|
||||
except json.decoder.JSONDecodeError:
|
||||
embed_json = "" # type: ignore
|
||||
|
||||
if embed_json:
|
||||
return get_embed_data(embed_json)
|
||||
|
||||
return CustomEmbed(
|
||||
title="",
|
||||
description="",
|
||||
color="",
|
||||
author_name="",
|
||||
author_url="",
|
||||
author_icon_url="",
|
||||
image_url="",
|
||||
thumbnail_url="",
|
||||
footer_text="",
|
||||
footer_icon_url="",
|
||||
)
|
||||
|
||||
|
||||
def get_embed_data(embed_data) -> CustomEmbed:
|
||||
"""Get embed data from embed_data.
|
||||
|
||||
Args:
|
||||
embed_data: The embed_data to get the data from.
|
||||
|
||||
Returns:
|
||||
Returns the embed data.
|
||||
"""
|
||||
title: str = embed_data.get("title", "")
|
||||
description: str = embed_data.get("description", "")
|
||||
color: str = embed_data.get("color", "")
|
||||
author_name: str = embed_data.get("author_name", "")
|
||||
author_url: str = embed_data.get("author_url", "")
|
||||
author_icon_url: str = embed_data.get("author_icon_url", "")
|
||||
image_url: str = embed_data.get("image_url", "")
|
||||
thumbnail_url: str = embed_data.get("thumbnail_url", "")
|
||||
footer_text: str = embed_data.get("footer_text", "")
|
||||
footer_icon_url: str = embed_data.get("footer_icon_url", "")
|
||||
|
||||
return CustomEmbed(
|
||||
title=title,
|
||||
description=description,
|
||||
color=color,
|
||||
author_name=author_name,
|
||||
author_url=author_url,
|
||||
author_icon_url=author_icon_url,
|
||||
image_url=image_url,
|
||||
thumbnail_url=thumbnail_url,
|
||||
footer_text=footer_text,
|
||||
footer_icon_url=footer_icon_url,
|
||||
)
|
||||
|
@ -1,6 +1,6 @@
|
||||
from typing import Iterable
|
||||
|
||||
from discord_webhook import DiscordWebhook
|
||||
from discord_webhook import DiscordEmbed, DiscordWebhook
|
||||
from reader import Entry, Feed, Reader
|
||||
from requests import Response
|
||||
|
||||
@ -45,18 +45,61 @@ def send_entry_to_discord(entry: Entry, custom_reader: Reader | None = None):
|
||||
|
||||
# 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
|
||||
webhook_message = custom_message.replace_tags_in_text_message(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)
|
||||
if bool(reader.get_tag(entry.feed, "should_send_embed")):
|
||||
webhook = create_embed_webhook(webhook_url, entry)
|
||||
else:
|
||||
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 create_embed_webhook(webhook_url: str, entry: Entry) -> DiscordWebhook:
|
||||
webhook: DiscordWebhook = DiscordWebhook(url=webhook_url, rate_limit_retry=True)
|
||||
feed: Feed = entry.feed
|
||||
|
||||
# Get the embed data from the database.
|
||||
custom_embed: custom_message.CustomEmbed = custom_message.replace_tags_in_embed(feed=feed, entry=entry)
|
||||
|
||||
discord_embed: DiscordEmbed = DiscordEmbed()
|
||||
|
||||
if custom_embed.title:
|
||||
discord_embed.set_title(custom_embed.title)
|
||||
if custom_embed.description:
|
||||
discord_embed.set_description(custom_embed.description)
|
||||
if custom_embed.color:
|
||||
discord_embed.set_color(custom_embed.color)
|
||||
if custom_embed.author_name and not custom_embed.author_url and not custom_embed.author_icon_url:
|
||||
discord_embed.set_author(name=custom_embed.author_name)
|
||||
if custom_embed.author_name and custom_embed.author_url and not custom_embed.author_icon_url:
|
||||
discord_embed.set_author(name=custom_embed.author_name, url=custom_embed.author_url)
|
||||
if custom_embed.author_name and not custom_embed.author_url and custom_embed.author_icon_url:
|
||||
discord_embed.set_author(name=custom_embed.author_name, icon_url=custom_embed.author_icon_url)
|
||||
if custom_embed.author_name and custom_embed.author_url and custom_embed.author_icon_url:
|
||||
discord_embed.set_author(name=custom_embed.author_name, url=custom_embed.author_url, icon_url=custom_embed.author_icon_url) # noqa: E501
|
||||
if custom_embed.thumbnail_url:
|
||||
discord_embed.set_thumbnail(url=custom_embed.thumbnail_url)
|
||||
if custom_embed.image_url:
|
||||
discord_embed.set_image(url=custom_embed.image_url)
|
||||
if custom_embed.footer_text:
|
||||
discord_embed.set_footer(text=custom_embed.footer_text)
|
||||
if custom_embed.footer_icon_url and custom_embed.footer_text:
|
||||
discord_embed.set_footer(text=custom_embed.footer_text, icon_url=custom_embed.footer_icon_url)
|
||||
if custom_embed.footer_icon_url and not custom_embed.footer_text:
|
||||
# TODO: Can this be done without a text?
|
||||
discord_embed.set_footer(icon_url=custom_embed.footer_icon_url)
|
||||
|
||||
webhook.add_embed(discord_embed)
|
||||
|
||||
return webhook
|
||||
|
||||
|
||||
def send_to_discord(custom_reader: Reader | None = None, feed: Feed | None = None, do_once: bool = False) -> None:
|
||||
"""
|
||||
Send entries to Discord.
|
||||
@ -93,15 +136,18 @@ def send_to_discord(custom_reader: Reader | None = None, feed: Feed | None = Non
|
||||
if not webhook_url:
|
||||
continue
|
||||
|
||||
# If the user has set the custom message to an empty string, we will use the default message, otherwise we will
|
||||
# use the custom message.
|
||||
if custom_message.get_custom_message(reader, entry.feed) != "":
|
||||
webhook_message = custom_message.replace_tags(entry=entry, feed=entry.feed) # type: ignore
|
||||
if bool(reader.get_tag(entry.feed, "should_send_embed")):
|
||||
webhook = create_embed_webhook(webhook_url, entry)
|
||||
else:
|
||||
webhook_message: str = default_custom_message
|
||||
# If the user has set the custom message to an empty string, we will use the default message, otherwise we
|
||||
# will use the custom message.
|
||||
if custom_message.get_custom_message(reader, entry.feed) != "":
|
||||
webhook_message = custom_message.replace_tags_in_text_message(entry=entry, feed=entry.feed)
|
||||
else:
|
||||
webhook_message: str = default_custom_message
|
||||
|
||||
# Create the webhook.
|
||||
webhook: DiscordWebhook = DiscordWebhook(url=webhook_url, content=webhook_message, rate_limit_retry=True)
|
||||
# Create the webhook.
|
||||
webhook: DiscordWebhook = DiscordWebhook(url=webhook_url, content=webhook_message, rate_limit_retry=True)
|
||||
|
||||
# Check if the feed has a whitelist, and if it does, check if the entry is whitelisted.
|
||||
if feed is not None and has_white_tags(reader, feed):
|
||||
|
@ -13,11 +13,19 @@ from starlette.responses import RedirectResponse
|
||||
|
||||
from discord_rss_bot import settings
|
||||
from discord_rss_bot.custom_filters import encode_url, entry_is_blacklisted, entry_is_whitelisted
|
||||
from discord_rss_bot.custom_message import get_custom_message, get_images_from_entry, replace_tags
|
||||
from discord_rss_bot.custom_message import (
|
||||
CustomEmbed,
|
||||
get_custom_message,
|
||||
get_embed,
|
||||
get_images_from_entry,
|
||||
replace_tags_in_text_message,
|
||||
save_embed,
|
||||
)
|
||||
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.markdown import convert_html_to_md
|
||||
from discord_rss_bot.missing_tags import add_missing_tags
|
||||
from discord_rss_bot.search import create_html_for_search_results
|
||||
from discord_rss_bot.settings import default_custom_message, get_reader, list_webhooks
|
||||
|
||||
@ -367,6 +375,125 @@ async def get_custom(feed_url, request: Request):
|
||||
return templates.TemplateResponse("custom.html", context)
|
||||
|
||||
|
||||
@app.get("/embed", response_class=HTMLResponse)
|
||||
async def get_embed_page(feed_url, request: Request):
|
||||
"""Get the custom message. This is used when sending the message to Discord.
|
||||
|
||||
Args:
|
||||
feed_url: What feed we should get the custom message for.
|
||||
request: The HTTP request.
|
||||
|
||||
Returns:
|
||||
custom.html
|
||||
"""
|
||||
|
||||
# Make feed_url a valid URL.
|
||||
url: str = urllib.parse.unquote(feed_url)
|
||||
|
||||
feed: Feed = reader.get_feed(url)
|
||||
|
||||
# Get previous data, this is used when creating the form.
|
||||
embed: CustomEmbed = get_embed(reader, feed)
|
||||
|
||||
context = {
|
||||
"request": request,
|
||||
"feed": feed,
|
||||
"title": embed.title,
|
||||
"description": embed.description,
|
||||
"color": embed.color,
|
||||
"image_url": embed.image_url,
|
||||
"thumbnail_url": embed.thumbnail_url,
|
||||
"author_name": embed.author_name,
|
||||
"author_url": embed.author_url,
|
||||
"author_icon_url": embed.author_icon_url,
|
||||
"footer_text": embed.footer_text,
|
||||
"footer_icon_url": embed.footer_icon_url,
|
||||
}
|
||||
|
||||
# Get the first entry, this is used to show the user what the custom message will look like.
|
||||
entries: Iterable[Entry] = reader.get_entries(feed=feed, limit=1)
|
||||
|
||||
if custom_embed := get_embed(reader, feed_url):
|
||||
context["custom_embed"] = custom_embed
|
||||
|
||||
for entry in entries:
|
||||
# Append to context.
|
||||
context["entry"] = entry
|
||||
return templates.TemplateResponse("embed.html", context)
|
||||
|
||||
|
||||
@app.post("/embed", response_class=HTMLResponse)
|
||||
async def set_embed_page(
|
||||
feed_url=Form(),
|
||||
title=Form(""),
|
||||
description=Form(""),
|
||||
color=Form(""),
|
||||
image_url=Form(""),
|
||||
thumbnail_url=Form(""),
|
||||
author_name=Form(""),
|
||||
author_url=Form(""),
|
||||
author_icon_url=Form(""),
|
||||
footer_text=Form(""),
|
||||
footer_icon_url=Form(""),
|
||||
):
|
||||
"""Set the embed settings.
|
||||
|
||||
Args:
|
||||
feed_url: What feed we should get the custom message for.
|
||||
request: The HTTP request.
|
||||
|
||||
Returns:
|
||||
custom.html
|
||||
"""
|
||||
|
||||
# Make feed_url a valid URL.
|
||||
url: str = urllib.parse.unquote(feed_url)
|
||||
|
||||
feed: Feed = reader.get_feed(url)
|
||||
|
||||
custom_embed: CustomEmbed = get_embed(reader, feed)
|
||||
|
||||
# Get the data from the form.
|
||||
custom_embed.title = title
|
||||
custom_embed.description = description
|
||||
custom_embed.color = color
|
||||
custom_embed.image_url = image_url
|
||||
custom_embed.thumbnail_url = thumbnail_url
|
||||
custom_embed.author_name = author_name
|
||||
custom_embed.author_url = author_url
|
||||
custom_embed.author_icon_url = author_icon_url
|
||||
custom_embed.footer_text = footer_text
|
||||
custom_embed.footer_icon_url = footer_icon_url
|
||||
|
||||
# Save the data.
|
||||
save_embed(reader, feed_url, custom_embed)
|
||||
|
||||
# Clean URL is used to redirect to the feed page.
|
||||
clean_url: str = urllib.parse.quote(feed_url)
|
||||
|
||||
return RedirectResponse(url=f"/feed/?feed_url={clean_url}", status_code=303)
|
||||
|
||||
|
||||
@app.post("/use_embed")
|
||||
async def set_should_use_embed(feed_url=Form()):
|
||||
url: str = urllib.parse.unquote(feed_url)
|
||||
print(f"Setting should_send_embed to True for {url}")
|
||||
|
||||
feed: Feed = reader.get_feed(url)
|
||||
reader.set_tag(feed, "should_send_embed", True) # type: ignore
|
||||
return RedirectResponse(url=f"/feed/?feed_url={feed_url}", status_code=303)
|
||||
|
||||
|
||||
@app.post("/use_text")
|
||||
async def set_should_use_text(feed_url=Form()):
|
||||
url: str = urllib.parse.unquote(feed_url)
|
||||
print(f"Setting should_send_embed to False for {url}")
|
||||
|
||||
feed: Feed = reader.get_feed(url)
|
||||
reader.set_tag(feed, "should_send_embed", False) # type: ignore
|
||||
return RedirectResponse(url=f"/feed/?feed_url={feed_url}", status_code=303)
|
||||
|
||||
|
||||
@app.get("/add", response_class=HTMLResponse)
|
||||
def get_add(request: Request):
|
||||
"""
|
||||
@ -408,7 +535,16 @@ async def get_feed(feed_url, request: Request):
|
||||
# Create the html for the entries.
|
||||
html: str = create_html_for_feed(entries)
|
||||
|
||||
context = {"request": request, "feed": feed, "entries": entries, "feed_counts": feed_counts, "html": html}
|
||||
should_send_embed: bool = bool(reader.get_tag(feed, "should_send_embed"))
|
||||
|
||||
context = {
|
||||
"request": request,
|
||||
"feed": feed,
|
||||
"entries": entries,
|
||||
"feed_counts": feed_counts,
|
||||
"html": html,
|
||||
"should_send_embed": should_send_embed,
|
||||
}
|
||||
return templates.TemplateResponse("feed.html", context)
|
||||
|
||||
|
||||
@ -433,7 +569,7 @@ def create_html_for_feed(entries: Iterable[Entry]) -> str:
|
||||
first_image_text: str = images[0][1]
|
||||
|
||||
# Get the text from the entry.
|
||||
text = replace_tags(entry.feed, entry)
|
||||
text = replace_tags_in_text_message(entry.feed, entry)
|
||||
if not text:
|
||||
text = "<div class='text-muted'>No content available.</div>"
|
||||
|
||||
@ -611,23 +747,7 @@ def startup() -> None:
|
||||
"""This is called when the server starts.
|
||||
|
||||
It reads the settings file and starts the scheduler."""
|
||||
# Add default feed message if it doesn't exist.
|
||||
# This was added in version 0.2.0.
|
||||
for feed in reader.get_feeds():
|
||||
try:
|
||||
reader.get_tag(feed, "custom_message")
|
||||
except TagNotFoundError:
|
||||
reader.set_tag(feed.url, "custom_message", default_custom_message) # type: ignore
|
||||
reader.set_tag(feed.url, "has_custom_message", True) # type: ignore
|
||||
|
||||
# Add has_custom_message tag if it doesn't exist.
|
||||
try:
|
||||
reader.get_tag(feed, "has_custom_message")
|
||||
except TagNotFoundError:
|
||||
if reader.get_tag(feed, "custom_message") == default_custom_message:
|
||||
reader.set_tag(feed.url, "has_custom_message", False) # type: ignore
|
||||
else:
|
||||
reader.set_tag(feed.url, "has_custom_message", True) # type: ignore
|
||||
add_missing_tags(reader=reader)
|
||||
|
||||
scheduler: BackgroundScheduler = BackgroundScheduler()
|
||||
|
||||
|
76
discord_rss_bot/missing_tags.py
Normal file
76
discord_rss_bot/missing_tags.py
Normal file
@ -0,0 +1,76 @@
|
||||
from reader import Feed, Reader, TagNotFoundError
|
||||
|
||||
from discord_rss_bot.settings import default_custom_embed, default_custom_message
|
||||
|
||||
|
||||
def add_custom_message(reader: Reader, feed: Feed) -> None:
|
||||
try:
|
||||
reader.get_tag(feed, "custom_message")
|
||||
except TagNotFoundError:
|
||||
print(f"Adding custom_message tag to '{feed.url}'")
|
||||
reader.set_tag(feed.url, "custom_message", default_custom_message) # type: ignore
|
||||
reader.set_tag(feed.url, "has_custom_message", True) # type: ignore
|
||||
|
||||
|
||||
def add_has_custom_message(reader: Reader, feed: Feed) -> None:
|
||||
try:
|
||||
reader.get_tag(feed, "has_custom_message")
|
||||
except TagNotFoundError:
|
||||
if reader.get_tag(feed, "custom_message") == default_custom_message:
|
||||
print(f"Setting has_custom_message tag to False for '{feed.url}'")
|
||||
reader.set_tag(feed.url, "has_custom_message", False) # type: ignore
|
||||
else:
|
||||
print(f"Setting has_custom_message tag to True for '{feed.url}'")
|
||||
reader.set_tag(feed.url, "has_custom_message", True) # type: ignore
|
||||
|
||||
|
||||
def add_if_embed(reader: Reader, feed: Feed) -> None:
|
||||
try:
|
||||
reader.get_tag(feed, "if_embed")
|
||||
except TagNotFoundError:
|
||||
print(f"Setting if_embed tag to True for '{feed.url}'")
|
||||
reader.set_tag(feed.url, "if_embed", True) # type: ignore
|
||||
|
||||
|
||||
def add_custom_embed(reader: Reader, feed: Feed) -> None:
|
||||
try:
|
||||
reader.get_tag(feed, "embed")
|
||||
except TagNotFoundError:
|
||||
print(f"Setting embed tag to default for '{feed.url}'")
|
||||
reader.set_tag(feed.url, "embed", default_custom_embed) # type: ignore
|
||||
reader.set_tag(feed.url, "has_custom_embed", True) # type: ignore
|
||||
|
||||
|
||||
def add_has_custom_embed(reader: Reader, feed: Feed) -> None:
|
||||
try:
|
||||
reader.get_tag(feed, "has_custom_embed")
|
||||
except TagNotFoundError:
|
||||
if reader.get_tag(feed, "embed") == default_custom_embed:
|
||||
print(f"Setting has_custom_embed tag to False for '{feed.url}'")
|
||||
reader.set_tag(feed.url, "has_custom_embed", False) # type: ignore
|
||||
else:
|
||||
print(f"Setting has_custom_embed tag to True for '{feed.url}'")
|
||||
reader.set_tag(feed.url, "has_custom_embed", True) # type: ignore
|
||||
|
||||
|
||||
def add_should_send_embed(reader: Reader, feed: Feed) -> None:
|
||||
try:
|
||||
reader.get_tag(feed, "should_send_embed")
|
||||
except TagNotFoundError:
|
||||
print(f"Setting should_send_embed tag to True for '{feed.url}'")
|
||||
reader.set_tag(feed.url, "should_send_embed", True) # type: ignore
|
||||
|
||||
|
||||
def add_missing_tags(reader: Reader) -> None:
|
||||
"""Add missing tags to feeds.
|
||||
|
||||
Args:
|
||||
reader: What Reader to use.
|
||||
"""
|
||||
for feed in reader.get_feeds():
|
||||
add_custom_message(reader, feed)
|
||||
add_has_custom_message(reader, feed)
|
||||
add_if_embed(reader, feed)
|
||||
add_custom_embed(reader, feed)
|
||||
add_has_custom_embed(reader, feed)
|
||||
add_should_send_embed(reader, feed)
|
@ -6,9 +6,7 @@ from reader import EntrySearchResult, Feed, HighlightedString, Reader
|
||||
from discord_rss_bot.settings import get_reader
|
||||
|
||||
|
||||
def create_html_for_search_results(
|
||||
search_results: Iterable[EntrySearchResult], custom_reader: Reader | None = None
|
||||
) -> str:
|
||||
def create_html_for_search_results(search_results: Iterable[EntrySearchResult], custom_reader: Reader | None = None) -> str:
|
||||
"""Create HTML for the search results.
|
||||
|
||||
Args:
|
||||
|
@ -7,7 +7,15 @@ from reader import Entry, Reader, TagNotFoundError, make_reader # type: ignore
|
||||
data_dir: str = user_data_dir(appname="discord_rss_bot", appauthor="TheLovinator", roaming=True)
|
||||
os.makedirs(data_dir, exist_ok=True)
|
||||
|
||||
# TODO: Add default things to the database and make the edible.
|
||||
default_custom_message: str = "{{entry_title}}\n{{entry_link}}"
|
||||
default_custom_embed = {
|
||||
"title": "{{entry_title}}",
|
||||
"description": "{{entry_content}}",
|
||||
"url": "{{entry_link}}",
|
||||
"image": "{{entry_image}}",
|
||||
"color": 0x008080,
|
||||
}
|
||||
|
||||
|
||||
def get_webhook_for_entry(custom_reader: Reader, entry: Entry) -> str:
|
||||
|
@ -236,9 +236,9 @@
|
||||
type="text"
|
||||
class="form-control bg-dark border-dark text-muted"
|
||||
id="custom_message"
|
||||
value="{% if custom_message %}
|
||||
{{- custom_message -}}
|
||||
{% endif %}"/>
|
||||
{% if custom_message %}
|
||||
value="{{- custom_message -}}"
|
||||
{% endif %}/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Add a hidden feed_url field to the form -->
|
||||
|
301
discord_rss_bot/templates/embed.html
Normal file
301
discord_rss_bot/templates/embed.html
Normal file
@ -0,0 +1,301 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}
|
||||
| Embed
|
||||
{% endblock title %}
|
||||
{% block content %}
|
||||
<div class="p-2 border border-dark">
|
||||
<form action="/embed" method="post">
|
||||
<div class="row pb-2">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-text">
|
||||
<ul class="list-inline">
|
||||
<br/>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{feed_author}}
|
||||
{% endraw %}
|
||||
</code>{{feed.author}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{feed_added}}
|
||||
{% endraw %}
|
||||
</code>{{feed.added}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{feed_last_exception}}
|
||||
{% endraw %}
|
||||
</code>{{feed.last_exception}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{feed_last_updated}}
|
||||
{% endraw %}
|
||||
</code>{{feed.last_updated}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{feed_link}}
|
||||
{% endraw %}
|
||||
</code>{{feed.link}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{feed_subtitle}}
|
||||
{% endraw %}
|
||||
</code>{{feed.subtitle}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{feed_title}}
|
||||
{% endraw %}
|
||||
</code>{{feed.title}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{feed_updated}}
|
||||
{% endraw %}
|
||||
</code>{{feed.updated}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{feed_updates_enabled}}
|
||||
{% endraw %}
|
||||
</code>{{feed.updates_enabled}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{feed_url}}
|
||||
{% endraw %}
|
||||
</code>{{feed.url}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{feed_user_title}}
|
||||
{% endraw %}
|
||||
</code>{{feed.user_title}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{feed_version}}
|
||||
{% endraw %}
|
||||
</code>{{feed.version}}
|
||||
</li>
|
||||
<br/>
|
||||
{% if entry %}
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_added}}
|
||||
{% endraw %}
|
||||
</code>{{entry.added}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_author}}
|
||||
{% endraw %}
|
||||
</code>{{entry.author}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_content}}
|
||||
{% endraw %}
|
||||
</code>{{entry.content[0].value|discord_markdown}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_content_raw}}
|
||||
{% endraw %}
|
||||
</code>{{entry.content[0].value}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_id}}
|
||||
{% endraw %}
|
||||
</code>{{entry.id}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_important}}
|
||||
{% endraw %}
|
||||
</code>{{entry.important}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_link}}
|
||||
{% endraw %}
|
||||
</code>{{entry.link}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_published}}
|
||||
{% endraw %}
|
||||
</code>{{entry.published}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_read}}
|
||||
{% endraw %}
|
||||
</code>{{entry.read}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_read_modified}}
|
||||
{% endraw %}
|
||||
</code>{{entry.read_modified}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_summary}}
|
||||
{% endraw %}
|
||||
</code>{{entry.summary|discord_markdown}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_summary_raw}}
|
||||
{% endraw %}
|
||||
</code>{{entry.summary}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_title}}
|
||||
{% endraw %}
|
||||
</code>{{entry.title}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_updated}}
|
||||
{% endraw %}
|
||||
</code>{{entry.updated}}
|
||||
</li>
|
||||
<br/>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{image_1}}
|
||||
{% endraw %}
|
||||
</code>First image in the entry if it exists
|
||||
</li>
|
||||
</ul>
|
||||
{% else %}
|
||||
Something went wrong, there was no entry found. If this feed has entries and you still see this message, please contact the developer.
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<label for="title" class="col-sm-6 col-form-label">Title</label>
|
||||
<input name="title"
|
||||
type="text"
|
||||
class="form-control bg-dark border-dark text-muted"
|
||||
id="title"
|
||||
{% if title %}
|
||||
value="{{- title -}}"
|
||||
{% endif %}/>
|
||||
<label for="description" class="col-sm-6 col-form-label">Description</label>
|
||||
<input name="description"
|
||||
type="text"
|
||||
class="form-control bg-dark border-dark text-muted"
|
||||
id="description"
|
||||
{% if description %}
|
||||
value="{{- description -}}"
|
||||
{% endif %}/>
|
||||
<label for="color" class="col-sm-6 col-form-label">Embed color</label>
|
||||
<input name="color"
|
||||
type="color"
|
||||
class="form-control form-control-color bg-dark border-dark text-muted"
|
||||
id="color"
|
||||
{% if color %}
|
||||
value="{{- color -}}"
|
||||
{% endif %}/>
|
||||
<label for="author_name" class="col-sm-6 col-form-label">Author name</label>
|
||||
<input name="author_name"
|
||||
type="text"
|
||||
class="form-control bg-dark border-dark text-muted"
|
||||
id="author_name"
|
||||
{% if author_name %}
|
||||
value="{{- author_name -}}"
|
||||
{% endif %}/>
|
||||
<label for="author_url" class="col-sm-6 col-form-label">Author URL</label>
|
||||
<input name="author_url"
|
||||
type="text"
|
||||
class="form-control bg-dark border-dark text-muted"
|
||||
id="author_url"
|
||||
{% if author_url %}
|
||||
value="{{- author_url -}}"
|
||||
{% endif %}/>
|
||||
<label for="author_icon_url" class="col-sm-6 col-form-label">Author icon URL</label>
|
||||
<input name="author_icon_url"
|
||||
type="text"
|
||||
class="form-control bg-dark border-dark text-muted"
|
||||
id="author_icon_url"
|
||||
{% if author_icon_url %}
|
||||
value="{{- author_icon_url -}}"
|
||||
{% endif %}/>
|
||||
<label for="image_url" class="col-sm-6 col-form-label">Image URL - Add {% raw %}{{image_1}}{% endraw %} for first image</label>
|
||||
<input name="image_url"
|
||||
type="text"
|
||||
class="form-control bg-dark border-dark text-muted"
|
||||
id="image_url"
|
||||
{% if image_url %}
|
||||
value="{{- image_url -}}"
|
||||
{% endif %}/>
|
||||
<label for="thumbnail_url" class="col-sm-6 col-form-label">Thumbnail</label>
|
||||
<input name="thumbnail_url"
|
||||
type="text"
|
||||
class="form-control bg-dark border-dark text-muted"
|
||||
id="thumbnail_url"
|
||||
{% if thumbnail_url %}
|
||||
value="{{- thumbnail_url -}}"
|
||||
{% endif %}/>
|
||||
<label for="footer_text" class="col-sm-6 col-form-label">Footer text</label>
|
||||
<input name="footer_text"
|
||||
type="text"
|
||||
class="form-control bg-dark border-dark text-muted"
|
||||
id="footer_text"
|
||||
{% if footer_text %}
|
||||
value="{{- footer_text -}}"
|
||||
{% endif %}/>
|
||||
<label for="footer_icon_url" class="col-sm-6 col-form-label">Footer icon</label>
|
||||
<input name="footer_icon_url"
|
||||
type="text"
|
||||
class="form-control bg-dark border-dark text-muted"
|
||||
id="footer_icon_url"
|
||||
{% if footer_icon_url %}
|
||||
value="{{- footer_icon_url -}}"
|
||||
{% endif %}/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Add a hidden feed_url field to the form -->
|
||||
<input type="hidden" name="feed_url" value="{{ feed.url }}"/>
|
||||
<!-- Submit button -->
|
||||
<div class="d-md-flex">
|
||||
<button class="btn btn-dark btn-sm">Update embed</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock content %}
|
@ -31,11 +31,33 @@
|
||||
<button class="btn btn-danger btn-sm" name="feed_url" value="{{ feed.url }}">Pause</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if should_send_embed == True %}
|
||||
<form action="/use_text" method="post">
|
||||
<button class="btn btn-dark btn-sm" name="feed_url" value="{{ feed.url }}">
|
||||
Send text messages instead of embeds
|
||||
</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<form action="/use_embed" method="post">
|
||||
<button class="btn btn-dark btn-sm" name="feed_url" value="{{ feed.url }}">
|
||||
Send embeds instead of text messages
|
||||
</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
<a class="text-muted"
|
||||
href="/whitelist?feed_url={{ feed.url|encode_url }}">Whitelist</a>
|
||||
<br/>
|
||||
<a class="text-muted"
|
||||
href="/blacklist?feed_url={{ feed.url|encode_url }}">Blacklist</a>
|
||||
<a class="text-muted" href="/custom?feed_url={{ feed.url|encode_url }}">Custom message</a>
|
||||
<br/>
|
||||
<a class="text-muted" href="/custom?feed_url={{ feed.url|encode_url }}">Customize message
|
||||
{% if not should_send_embed %}(Active){% endif %}
|
||||
</a>
|
||||
<br/>
|
||||
<a class="text-muted" href="/embed?feed_url={{ feed.url|encode_url }}">Customize embed
|
||||
{% if should_send_embed %}(Active){% endif %}
|
||||
</a>
|
||||
<br/>
|
||||
</div>
|
||||
{# HTML is created in main.create_html_for_feed #}
|
||||
<pre>
|
||||
|
Reference in New Issue
Block a user