Stuff and things
This commit is contained in:
@ -3,7 +3,7 @@ from functools import lru_cache
|
||||
|
||||
from reader import Entry, Reader
|
||||
|
||||
from discord_rss_bot.filter.blacklist import has_black_tags, should_be_skipped
|
||||
from discord_rss_bot.filter.blacklist import entry_should_be_skipped, feed_has_blacklist_tags
|
||||
from discord_rss_bot.filter.whitelist import has_white_tags, should_be_sent
|
||||
from discord_rss_bot.settings import get_reader
|
||||
|
||||
@ -24,7 +24,7 @@ def encode_url(url_to_quote: str) -> str:
|
||||
Returns:
|
||||
The encoded url.
|
||||
"""
|
||||
return urllib.parse.quote(url_to_quote) if url_to_quote else ""
|
||||
return urllib.parse.quote(string=url_to_quote) if url_to_quote else ""
|
||||
|
||||
|
||||
def entry_is_whitelisted(entry_to_check: Entry) -> bool:
|
||||
@ -50,4 +50,6 @@ def entry_is_blacklisted(entry_to_check: Entry) -> bool:
|
||||
bool: True if the feed is blacklisted, False otherwise.
|
||||
|
||||
"""
|
||||
return bool(has_black_tags(reader, entry_to_check.feed) and should_be_skipped(reader, entry_to_check))
|
||||
return bool(
|
||||
feed_has_blacklist_tags(reader, entry_to_check.feed) and entry_should_be_skipped(reader, entry_to_check),
|
||||
)
|
||||
|
@ -42,6 +42,7 @@ def try_to_replace(custom_message: str, template: str, replace_with: str) -> str
|
||||
try:
|
||||
return custom_message.replace(template, replace_with)
|
||||
except (TypeError, AttributeError, ValueError):
|
||||
logger.exception("Failed to replace %s with %s in %s", template, replace_with, custom_message)
|
||||
return custom_message
|
||||
|
||||
|
||||
@ -78,39 +79,52 @@ def replace_tags_in_text_message(entry: Entry) -> str:
|
||||
summary = summary.replace("[https://", "[")
|
||||
summary = summary.replace("[https://www.", "[")
|
||||
|
||||
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},
|
||||
feed_added: str = feed.added.strftime("%Y-%m-%d %H:%M:%S") if feed.added else "Never"
|
||||
feed_last_exception: str = feed.last_exception.value_str if feed.last_exception else ""
|
||||
feed_last_updated: str = feed.last_updated.strftime("%Y-%m-%d %H:%M:%S") if feed.last_updated else "Never"
|
||||
feed_updated: str = feed.updated.strftime("%Y-%m-%d %H:%M:%S") if feed.updated else "Never"
|
||||
entry_added: str = entry.added.strftime("%Y-%m-%d %H:%M:%S") if entry.added else "Never"
|
||||
entry_published: str = entry.published.strftime("%Y-%m-%d %H:%M:%S") if entry.published else "Never"
|
||||
entry_read_modified: str = entry.read_modified.strftime("%Y-%m-%d %H:%M:%S") if entry.read_modified else "Never"
|
||||
entry_updated: str = entry.updated.strftime("%Y-%m-%d %H:%M:%S") if entry.updated else "Never"
|
||||
|
||||
list_of_replacements: list[dict[str, str]] = [
|
||||
{"{{feed_author}}": feed.author or ""},
|
||||
{"{{feed_added}}": feed_added},
|
||||
{"{{feed_last_exception}}": feed_last_exception},
|
||||
{"{{feed_last_updated}}": feed_last_updated},
|
||||
{"{{feed_link}}": feed.link or ""},
|
||||
{"{{feed_subtitle}}": feed.subtitle or ""},
|
||||
{"{{feed_title}}": feed.title or ""},
|
||||
{"{{feed_updated}}": feed_updated},
|
||||
{"{{feed_updates_enabled}}": str(feed.updates_enabled) or ""},
|
||||
{"{{feed_url}}": feed.url or ""},
|
||||
{"{{feed_user_title}}": feed.user_title or ""},
|
||||
{"{{feed_version}}": feed.version or ""},
|
||||
{"{{entry_added}}": entry_added},
|
||||
{"{{entry_author}}": entry.author or ""},
|
||||
{"{{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_id}}": entry.id or ""},
|
||||
{"{{entry_important}}": str(entry.important) or ""},
|
||||
{"{{entry_link}}": entry.link or ""},
|
||||
{"{{entry_published}}": entry_published},
|
||||
{"{{entry_read}}": str(entry.read) or ""},
|
||||
{"{{entry_read_modified}}": entry_read_modified},
|
||||
{"{{entry_summary}}": summary},
|
||||
{"{{entry_summary_raw}}": entry.summary or ""},
|
||||
{"{{entry_text}}": summary or content},
|
||||
{"{{entry_title}}": entry.title},
|
||||
{"{{entry_updated}}": entry.updated},
|
||||
{"{{entry_title}}": entry.title or ""},
|
||||
{"{{entry_updated}}": entry_updated},
|
||||
{"{{image_1}}": first_image},
|
||||
]
|
||||
|
||||
for replacement in list_of_replacements:
|
||||
for template, replace_with in replacement.items():
|
||||
if not isinstance(replace_with, str):
|
||||
logger.error("replace_with is not a string: %s, it is a %s", replace_with, type(replace_with))
|
||||
continue
|
||||
|
||||
custom_message = try_to_replace(custom_message, template, replace_with)
|
||||
|
||||
return custom_message.replace("\\n", "\n")
|
||||
@ -200,9 +214,18 @@ def replace_tags_in_embed(feed: Feed, entry: Entry) -> CustomEmbed:
|
||||
embed.author_name = embed.title
|
||||
embed.title = ""
|
||||
|
||||
feed_added: str = feed.added.strftime("%Y-%m-%d %H:%M:%S") if feed.added else "Never"
|
||||
feed_last_exception: str = feed.last_exception.value_str if feed.last_exception else ""
|
||||
feed_last_updated: str = feed.last_updated.strftime("%Y-%m-%d %H:%M:%S") if feed.last_updated else "Never"
|
||||
feed_updated: str = feed.updated.strftime("%Y-%m-%d %H:%M:%S") if feed.updated else "Never"
|
||||
entry_published: str = entry.published.strftime("%Y-%m-%d %H:%M:%S") if entry.published else "Never"
|
||||
entry_read_modified: str = entry.read_modified.strftime("%Y-%m-%d %H:%M:%S") if entry.read_modified else "Never"
|
||||
entry_updated: str = entry.updated.strftime("%Y-%m-%d %H:%M:%S") if entry.updated else "Never"
|
||||
|
||||
list_of_replacements: list[dict[str, str]] = [
|
||||
{"{{feed_author}}": feed.author or ""},
|
||||
{"{{feed_added}}": feed_added or ""},
|
||||
{"{{feed_last_exception}}": feed_last_exception},
|
||||
{"{{feed_last_updated}}": feed_last_updated or ""},
|
||||
{"{{feed_link}}": feed.link or ""},
|
||||
{"{{feed_subtitle}}": feed.subtitle or ""},
|
||||
@ -308,7 +331,9 @@ def get_embed(custom_reader: Reader, feed: Feed) -> CustomEmbed:
|
||||
Returns:
|
||||
Returns the contents from the embed tag.
|
||||
"""
|
||||
if embed := custom_reader.get_tag(feed, "embed", ""):
|
||||
embed = custom_reader.get_tag(feed, "embed", "")
|
||||
|
||||
if embed:
|
||||
if not isinstance(embed, str):
|
||||
return get_embed_data(embed) # type: ignore
|
||||
embed_data: dict[str, str | int] = json.loads(embed)
|
||||
|
@ -7,12 +7,13 @@ from typing import TYPE_CHECKING
|
||||
|
||||
from discord_webhook import DiscordEmbed, DiscordWebhook
|
||||
from fastapi import HTTPException
|
||||
from reader import Entry, EntryNotFoundError, Feed, FeedExistsError, Reader, StorageError, TagNotFoundError
|
||||
from reader import Entry, EntryNotFoundError, Feed, FeedExistsError, Reader, ReaderError, StorageError, TagNotFoundError
|
||||
|
||||
from discord_rss_bot import custom_message
|
||||
from discord_rss_bot.filter.blacklist import should_be_skipped
|
||||
from discord_rss_bot.filter.blacklist import entry_should_be_skipped
|
||||
from discord_rss_bot.filter.whitelist import has_white_tags, should_be_sent
|
||||
from discord_rss_bot.is_url_valid import is_url_valid
|
||||
from discord_rss_bot.missing_tags import add_missing_tags
|
||||
from discord_rss_bot.settings import default_custom_message, get_reader
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -50,15 +51,21 @@ def send_entry_to_discord(entry: Entry, custom_reader: Reader | None = None) ->
|
||||
webhook_message = "No message found."
|
||||
|
||||
# Create the webhook.
|
||||
if bool(reader.get_tag(entry.feed, "should_send_embed")):
|
||||
try:
|
||||
should_send_embed = bool(reader.get_tag(entry.feed, "should_send_embed"))
|
||||
except TagNotFoundError:
|
||||
logger.exception("No should_send_embed tag found for feed: %s", entry.feed.url)
|
||||
should_send_embed = True
|
||||
except StorageError:
|
||||
logger.exception("Error getting should_send_embed tag for feed: %s", entry.feed.url)
|
||||
should_send_embed = True
|
||||
|
||||
if 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 response.status_code not in {200, 204}:
|
||||
logger.error("Error sending entry to Discord: %s\n%s", response.text, pprint.pformat(webhook.json))
|
||||
return f"Error sending entry to Discord: {response.text}"
|
||||
execute_webhook(webhook, entry)
|
||||
return None
|
||||
|
||||
|
||||
@ -159,7 +166,43 @@ def create_embed_webhook(webhook_url: str, entry: Entry) -> DiscordWebhook:
|
||||
return webhook
|
||||
|
||||
|
||||
def send_to_discord(custom_reader: Reader | None = None, feed: Feed | None = None, *, do_once: bool = False) -> None: # noqa: PLR0912
|
||||
def get_webhook_url(reader: Reader, entry: Entry) -> str:
|
||||
"""Get the webhook URL for the entry.
|
||||
|
||||
Args:
|
||||
reader: The reader to use.
|
||||
entry: The entry to get the webhook URL for.
|
||||
|
||||
Returns:
|
||||
str: The webhook URL.
|
||||
"""
|
||||
try:
|
||||
webhook_url: str = str(reader.get_tag(entry.feed_url, "webhook"))
|
||||
except TagNotFoundError:
|
||||
logger.exception("No webhook URL found for feed: %s", entry.feed.url)
|
||||
return ""
|
||||
except StorageError:
|
||||
logger.exception("Storage error getting webhook URL for feed: %s", entry.feed.url)
|
||||
return ""
|
||||
return webhook_url
|
||||
|
||||
|
||||
def set_entry_as_read(reader: Reader, entry: Entry) -> None:
|
||||
"""Set the webhook to read, so we don't send it again.
|
||||
|
||||
Args:
|
||||
reader: The reader to use.
|
||||
entry: The entry to set as read.
|
||||
"""
|
||||
try:
|
||||
reader.set_entry_read(entry, True)
|
||||
except EntryNotFoundError:
|
||||
logger.exception("Error setting entry to read: %s", entry.id)
|
||||
except StorageError:
|
||||
logger.exception("Error setting entry to read: %s", entry.id)
|
||||
|
||||
|
||||
def send_to_discord(custom_reader: Reader | None = None, feed: Feed | None = None, *, do_once: bool = False) -> None:
|
||||
"""Send entries to Discord.
|
||||
|
||||
If response was not ok, we will log the error and mark the entry as unread, so it will be sent again next time.
|
||||
@ -178,27 +221,19 @@ def send_to_discord(custom_reader: Reader | None = None, feed: Feed | None = Non
|
||||
# Loop through the unread entries.
|
||||
entries: Iterable[Entry] = reader.get_entries(feed=feed, read=False)
|
||||
for entry in entries:
|
||||
set_entry_as_read(reader, entry)
|
||||
|
||||
if entry.added < datetime.datetime.now(tz=entry.added.tzinfo) - datetime.timedelta(days=1):
|
||||
logger.info("Entry is older than 24 hours: %s from %s", entry.id, entry.feed.url)
|
||||
reader.set_entry_read(entry, True)
|
||||
continue
|
||||
|
||||
# Set the webhook to read, so we don't send it again.
|
||||
try:
|
||||
reader.set_entry_read(entry, True)
|
||||
except EntryNotFoundError:
|
||||
logger.exception("Error setting entry to read: %s", entry.id)
|
||||
continue
|
||||
except StorageError:
|
||||
logger.exception("Error setting entry to read: %s", entry.id)
|
||||
continue
|
||||
|
||||
# Get the webhook URL for the entry. If it is None, we will continue to the next entry.
|
||||
webhook_url: str = str(reader.get_tag(entry.feed_url, "webhook", ""))
|
||||
webhook_url: str = get_webhook_url(reader, entry)
|
||||
if not webhook_url:
|
||||
logger.info("No webhook URL found for feed: %s", entry.feed.url)
|
||||
continue
|
||||
|
||||
if bool(reader.get_tag(entry.feed, "should_send_embed")):
|
||||
should_send_embed: bool = should_send_embed_check(reader, entry)
|
||||
if should_send_embed:
|
||||
webhook = create_embed_webhook(webhook_url, entry)
|
||||
else:
|
||||
# If the user has set the custom message to an empty string, we will use the default message, otherwise we
|
||||
@ -208,49 +243,87 @@ def send_to_discord(custom_reader: Reader | None = None, feed: Feed | None = Non
|
||||
else:
|
||||
webhook_message: str = str(default_custom_message)
|
||||
|
||||
# Its actually 4096, but we will use 4000 to be safe.
|
||||
max_content_length: int = 4000
|
||||
webhook_message = (
|
||||
f"{webhook_message[:max_content_length]}..."
|
||||
if len(webhook_message) > max_content_length
|
||||
else webhook_message
|
||||
)
|
||||
webhook_message = truncate_webhook_message(webhook_message)
|
||||
|
||||
# Create the webhook.
|
||||
webhook: DiscordWebhook = DiscordWebhook(url=webhook_url, content=webhook_message, rate_limit_retry=True)
|
||||
|
||||
# Check if the entry is blacklisted, if it is, mark it as read and continue.
|
||||
if should_be_skipped(reader, entry):
|
||||
# Check if the entry is blacklisted, and if it is, we will skip it.
|
||||
if entry_should_be_skipped(reader, entry):
|
||||
logger.info("Entry was blacklisted: %s", entry.id)
|
||||
reader.set_entry_read(entry, True)
|
||||
continue
|
||||
|
||||
# Check if the feed has a whitelist, and if it does, check if the entry is whitelisted.
|
||||
if has_white_tags(reader, entry.feed):
|
||||
if should_be_sent(reader, entry):
|
||||
response: Response = webhook.execute()
|
||||
if response.status_code not in {200, 204}:
|
||||
logger.error("Error sending entry to Discord: %s\n%s", response.text, pprint.pformat(webhook.json))
|
||||
|
||||
reader.set_entry_read(entry, True)
|
||||
execute_webhook(webhook, entry)
|
||||
return
|
||||
reader.set_entry_read(entry, True)
|
||||
continue
|
||||
|
||||
# It was not blacklisted, and not forced through whitelist, so we will send it to Discord.
|
||||
response: Response = webhook.execute()
|
||||
if response.status_code not in {200, 204}:
|
||||
logger.error("Error sending entry to Discord: %s\n%s", response.text, pprint.pformat(webhook.json))
|
||||
reader.set_entry_read(entry, True)
|
||||
return
|
||||
# Send the entry to Discord as it is not blacklisted or feed has a whitelist.
|
||||
execute_webhook(webhook, entry)
|
||||
|
||||
# If we only want to send one entry, we will break the loop. This is used when testing this function.
|
||||
if do_once:
|
||||
logger.info("Sent one entry to Discord.")
|
||||
logger.info("Sent one entry to Discord. Breaking the loop.")
|
||||
break
|
||||
|
||||
# Update the search index.
|
||||
reader.update_search()
|
||||
|
||||
def execute_webhook(webhook: DiscordWebhook, entry: Entry) -> None:
|
||||
"""Execute the webhook.
|
||||
|
||||
Args:
|
||||
webhook (DiscordWebhook): The webhook to execute.
|
||||
entry (Entry): The entry to send to Discord.
|
||||
|
||||
"""
|
||||
response: Response = webhook.execute()
|
||||
if response.status_code not in {200, 204}:
|
||||
msg: str = f"Error sending entry to Discord: {response.text}\n{pprint.pformat(webhook.json)}"
|
||||
if entry:
|
||||
msg += f"\n{entry}"
|
||||
|
||||
logger.error(msg)
|
||||
else:
|
||||
logger.info("Sent entry to Discord: %s", entry.id)
|
||||
|
||||
|
||||
def should_send_embed_check(reader: Reader, entry: Entry) -> bool:
|
||||
"""Check if we should send an embed to Discord.
|
||||
|
||||
Args:
|
||||
reader (Reader): The reader to use.
|
||||
entry (Entry): The entry to check.
|
||||
|
||||
Returns:
|
||||
bool: True if we should send an embed, False otherwise.
|
||||
"""
|
||||
try:
|
||||
should_send_embed = bool(reader.get_tag(entry.feed, "should_send_embed"))
|
||||
except TagNotFoundError:
|
||||
logger.exception("No should_send_embed tag found for feed: %s", entry.feed.url)
|
||||
should_send_embed = True
|
||||
except ReaderError:
|
||||
logger.exception("Error getting should_send_embed tag for feed: %s", entry.feed.url)
|
||||
should_send_embed = True
|
||||
|
||||
return should_send_embed
|
||||
|
||||
|
||||
def truncate_webhook_message(webhook_message: str) -> str:
|
||||
"""Truncate the webhook message if it is too long.
|
||||
|
||||
Args:
|
||||
webhook_message (str): The webhook message to truncate.
|
||||
|
||||
Returns:
|
||||
str: The truncated webhook message.
|
||||
"""
|
||||
max_content_length: int = 4000
|
||||
if len(webhook_message) > max_content_length:
|
||||
half_length = (max_content_length - 3) // 2 # Subtracting 3 for the "..." in the middle
|
||||
webhook_message = f"{webhook_message[:half_length]}...{webhook_message[-half_length:]}"
|
||||
return webhook_message
|
||||
|
||||
|
||||
def create_feed(reader: Reader, feed_url: str, webhook_dropdown: str) -> None:
|
||||
@ -277,7 +350,6 @@ def create_feed(reader: Reader, feed_url: str, webhook_dropdown: str) -> None:
|
||||
raise HTTPException(status_code=404, detail="Webhook not found")
|
||||
|
||||
try:
|
||||
# TODO(TheLovinator): Check if the feed is valid
|
||||
reader.add_feed(clean_feed_url)
|
||||
except FeedExistsError:
|
||||
# Add the webhook to an already added feed if it doesn't have a webhook instead of trying to create a new.
|
||||
@ -285,8 +357,13 @@ def create_feed(reader: Reader, feed_url: str, webhook_dropdown: str) -> None:
|
||||
reader.get_tag(clean_feed_url, "webhook")
|
||||
except TagNotFoundError:
|
||||
reader.set_tag(clean_feed_url, "webhook", webhook_url) # type: ignore
|
||||
except ReaderError as e:
|
||||
raise HTTPException(status_code=404, detail=f"Error adding feed: {e}") from e
|
||||
|
||||
reader.update_feed(clean_feed_url)
|
||||
try:
|
||||
reader.update_feed(clean_feed_url)
|
||||
except ReaderError as e:
|
||||
raise HTTPException(status_code=404, detail=f"Error updating feed: {e}") from e
|
||||
|
||||
# Mark every entry as read, so we don't send all the old entries to Discord.
|
||||
entries: Iterable[Entry] = reader.get_entries(feed=clean_feed_url, read=False)
|
||||
@ -305,3 +382,5 @@ def create_feed(reader: Reader, feed_url: str, webhook_dropdown: str) -> None:
|
||||
|
||||
# Update the full-text search index so our new feed is searchable.
|
||||
reader.update_search()
|
||||
|
||||
add_missing_tags(reader)
|
||||
|
@ -3,7 +3,7 @@ from reader import Entry, Feed, Reader
|
||||
from discord_rss_bot.filter.utils import is_word_in_text
|
||||
|
||||
|
||||
def has_black_tags(custom_reader: Reader, feed: Feed) -> bool:
|
||||
def feed_has_blacklist_tags(custom_reader: Reader, feed: Feed) -> bool:
|
||||
"""Return True if the feed has blacklist tags.
|
||||
|
||||
The following tags are checked:
|
||||
@ -25,7 +25,7 @@ def has_black_tags(custom_reader: Reader, feed: Feed) -> bool:
|
||||
return bool(blacklist_title or blacklist_summary or blacklist_content)
|
||||
|
||||
|
||||
def should_be_skipped(custom_reader: Reader, entry: Entry) -> bool:
|
||||
def entry_should_be_skipped(custom_reader: Reader, entry: Entry) -> bool:
|
||||
"""Return True if the entry is in the blacklist.
|
||||
|
||||
Args:
|
||||
@ -35,11 +35,10 @@ def should_be_skipped(custom_reader: Reader, entry: Entry) -> bool:
|
||||
Returns:
|
||||
bool: If the entry is in the blacklist.
|
||||
"""
|
||||
feed: Feed = entry.feed
|
||||
blacklist_title: str = str(custom_reader.get_tag(feed, "blacklist_title", ""))
|
||||
blacklist_summary: str = str(custom_reader.get_tag(feed, "blacklist_summary", ""))
|
||||
blacklist_content: str = str(custom_reader.get_tag(feed, "blacklist_content", ""))
|
||||
blacklist_author: str = str(custom_reader.get_tag(feed, "blacklist_author", ""))
|
||||
blacklist_title: str = str(custom_reader.get_tag(entry.feed, "blacklist_title", ""))
|
||||
blacklist_summary: str = str(custom_reader.get_tag(entry.feed, "blacklist_summary", ""))
|
||||
blacklist_content: str = str(custom_reader.get_tag(entry.feed, "blacklist_content", ""))
|
||||
blacklist_author: str = str(custom_reader.get_tag(entry.feed, "blacklist_author", ""))
|
||||
# TODO(TheLovinator): Also add support for entry_text and more.
|
||||
|
||||
if entry.title and blacklist_title and is_word_in_text(blacklist_title, entry.title):
|
||||
|
@ -3,23 +3,20 @@ from __future__ import annotations
|
||||
import re
|
||||
|
||||
|
||||
def is_word_in_text(words: str, text: str) -> bool:
|
||||
"""Check if the word is in the text.
|
||||
def is_word_in_text(word_string: str, text: str) -> bool:
|
||||
"""Check if any of the words are in the text.
|
||||
|
||||
Args:
|
||||
words: The words to search for.
|
||||
word_string: A comma-separated string of words to search for.
|
||||
text: The text to search in.
|
||||
|
||||
Returns:
|
||||
bool: If the word is in the text.
|
||||
bool: True if any word is found in the text, otherwise False.
|
||||
"""
|
||||
# Split the word list into a list of words.
|
||||
word_list: list[str] = words.split(",")
|
||||
word_list: list[str] = word_string.split(",")
|
||||
|
||||
# Check if each word is in the text.
|
||||
for word in word_list:
|
||||
look_for: str = rf"(^|[^\w]){word}([^\w]|$)"
|
||||
pattern: re.Pattern[str] = re.compile(look_for, re.IGNORECASE)
|
||||
if re.search(pattern, text):
|
||||
return True
|
||||
return False
|
||||
# Compile regex patterns for each word.
|
||||
patterns: list[re.Pattern[str]] = [re.compile(rf"(^|[^\w]){word}([^\w]|$)", re.IGNORECASE) for word in word_list]
|
||||
|
||||
# Check if any pattern matches the text.
|
||||
return any(pattern.search(text) for pattern in patterns)
|
||||
|
@ -20,13 +20,12 @@ from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from httpx import Response
|
||||
from markdownify import markdownify
|
||||
from reader import Entry, Feed, FeedNotFoundError, Reader, TagNotFoundError
|
||||
from reader import Entry, EntryNotFoundError, Feed, FeedNotFoundError, Reader, TagNotFoundError
|
||||
from reader.types import JSONType
|
||||
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,
|
||||
)
|
||||
@ -42,7 +41,6 @@ from discord_rss_bot.feeds import create_feed, send_entry_to_discord, send_to_di
|
||||
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 get_reader
|
||||
from discord_rss_bot.webhook import add_webhook, remove_webhook
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Iterable
|
||||
@ -90,7 +88,7 @@ reader: Reader = get_reader()
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI) -> typing.AsyncGenerator[None]:
|
||||
"""This is needed for the ASGI server to run."""
|
||||
add_missing_tags(reader=reader)
|
||||
add_missing_tags(reader)
|
||||
scheduler: AsyncIOScheduler = AsyncIOScheduler()
|
||||
|
||||
# Update all feeds every 15 minutes.
|
||||
@ -109,7 +107,7 @@ templates: Jinja2Templates = Jinja2Templates(directory="discord_rss_bot/template
|
||||
|
||||
|
||||
# Add the filters to the Jinja2 environment so they can be used in html templates.
|
||||
templates.env.filters["encode_url"] = encode_url
|
||||
templates.env.filters["encode_url"] = lambda url: urllib.parse.quote(url) if url else ""
|
||||
templates.env.filters["entry_is_whitelisted"] = entry_is_whitelisted
|
||||
templates.env.filters["entry_is_blacklisted"] = entry_is_blacklisted
|
||||
templates.env.filters["discord_markdown"] = markdownify
|
||||
@ -126,11 +124,32 @@ async def post_add_webhook(
|
||||
webhook_name: The name of the webhook.
|
||||
webhook_url: The url of the webhook.
|
||||
|
||||
Raises:
|
||||
HTTPException: If the webhook already exists.
|
||||
|
||||
Returns:
|
||||
RedirectResponse: Redirect to the index page.
|
||||
"""
|
||||
add_webhook(reader, webhook_name, webhook_url)
|
||||
return RedirectResponse(url="/", status_code=303)
|
||||
# Get current webhooks from the database if they exist otherwise use an empty list.
|
||||
webhooks = list(reader.get_tag((), "webhooks", []))
|
||||
|
||||
# Webhooks are stored as a list of dictionaries.
|
||||
# Example: [{"name": "webhook_name", "url": "webhook_url"}]
|
||||
webhooks = cast(list[dict[str, str]], webhooks)
|
||||
|
||||
# Only add the webhook if it doesn't already exist.
|
||||
stripped_webhook_name = webhook_name.strip()
|
||||
if all(webhook["name"] != stripped_webhook_name for webhook in webhooks):
|
||||
# Add the new webhook to the list of webhooks.
|
||||
webhooks.append({"name": webhook_name.strip(), "url": webhook_url.strip()})
|
||||
|
||||
reader.set_tag((), "webhooks", webhooks) # type: ignore
|
||||
|
||||
return RedirectResponse(url="/", status_code=303)
|
||||
|
||||
# TODO(TheLovinator): Show this error on the page.
|
||||
# TODO(TheLovinator): Replace HTTPException with WebhookAlreadyExistsError.
|
||||
raise HTTPException(status_code=409, detail="Webhook already exists")
|
||||
|
||||
|
||||
@app.post("/delete_webhook")
|
||||
@ -140,11 +159,37 @@ async def post_delete_webhook(webhook_url: Annotated[str, Form()]) -> RedirectRe
|
||||
Args:
|
||||
webhook_url: The url of the webhook.
|
||||
|
||||
Raises:
|
||||
HTTPException: If the webhook could not be deleted
|
||||
|
||||
Returns:
|
||||
RedirectResponse: Redirect to the index page.
|
||||
"""
|
||||
# TODO(TheLovinator): Check if the webhook is in use by any feeds before deleting it.
|
||||
remove_webhook(reader, webhook_url)
|
||||
# TODO(TheLovinator): Replace HTTPException with a custom exception for both of these.
|
||||
# Get current webhooks from the database if they exist otherwise use an empty list.
|
||||
webhooks = list(reader.get_tag((), "webhooks", []))
|
||||
|
||||
# Webhooks are stored as a list of dictionaries.
|
||||
# Example: [{"name": "webhook_name", "url": "webhook_url"}]
|
||||
webhooks = cast(list[dict[str, str]], webhooks)
|
||||
|
||||
# Only add the webhook if it doesn't already exist.
|
||||
webhooks_to_remove: list[dict[str, str]] = [
|
||||
webhook for webhook in webhooks if webhook["url"] == webhook_url.strip()
|
||||
]
|
||||
|
||||
# Remove the webhooks outside the loop.
|
||||
for webhook in webhooks_to_remove:
|
||||
webhooks.remove(webhook)
|
||||
|
||||
# Check if any webhooks were removed.
|
||||
if not all(webhook not in webhooks for webhook in webhooks_to_remove):
|
||||
raise HTTPException(status_code=500, detail="Webhook could not be deleted")
|
||||
|
||||
# Add our new list of webhooks to the database.
|
||||
reader.set_tag((), "webhooks", webhooks) # type: ignore
|
||||
|
||||
return RedirectResponse(url="/", status_code=303)
|
||||
|
||||
|
||||
@ -515,7 +560,7 @@ def get_add(request: Request):
|
||||
|
||||
|
||||
@app.get("/feed", response_class=HTMLResponse)
|
||||
async def get_feed(feed_url: str, request: Request, starting_after: str | None = None):
|
||||
async def get_feed(feed_url: str, request: Request, starting_after: str = ""):
|
||||
"""Get a feed by URL.
|
||||
|
||||
Args:
|
||||
@ -523,15 +568,65 @@ async def get_feed(feed_url: str, request: Request, starting_after: str | None =
|
||||
request: The request object.
|
||||
starting_after: The entry to start after. Used for pagination.
|
||||
|
||||
Raises:
|
||||
HTTPException: If the feed is not found.
|
||||
|
||||
Returns:
|
||||
HTMLResponse: The feed page.
|
||||
"""
|
||||
entries_per_page: int = 20
|
||||
|
||||
clean_feed_url: str = urllib.parse.unquote(feed_url.strip())
|
||||
|
||||
feed: Feed = reader.get_feed(clean_feed_url)
|
||||
try:
|
||||
feed: Feed = reader.get_feed(clean_feed_url)
|
||||
except FeedNotFoundError as e:
|
||||
raise HTTPException(status_code=404, detail=f"Feed '{clean_feed_url}' not found.\n\n{e}") from e
|
||||
|
||||
# Only show button if more than 10 entries.
|
||||
total_entries: int = reader.get_entry_counts(feed=feed).total or 0
|
||||
show_more_entires_button: bool = total_entries > entries_per_page
|
||||
|
||||
# Get entries from the feed.
|
||||
entries: typing.Iterable[Entry] = reader.get_entries(feed=clean_feed_url, limit=10)
|
||||
if starting_after:
|
||||
try:
|
||||
start_after_entry: Entry | None = reader.get_entry((str(feed.url), starting_after))
|
||||
except FeedNotFoundError as e:
|
||||
raise HTTPException(status_code=404, detail=f"Feed '{clean_feed_url}' not found.\n\n{e}") from e
|
||||
except EntryNotFoundError as e:
|
||||
current_entries = list(reader.get_entries(feed=clean_feed_url))
|
||||
msg: str = f"{e}\n\n{[entry.id for entry in current_entries]}"
|
||||
html: str = create_html_for_feed(current_entries)
|
||||
|
||||
context = {
|
||||
"request": request,
|
||||
"feed": feed,
|
||||
"entries": current_entries,
|
||||
"feed_counts": reader.get_feed_counts(feed=clean_feed_url),
|
||||
"html": html,
|
||||
"should_send_embed": False,
|
||||
"last_entry": None,
|
||||
"messages": msg,
|
||||
"show_more_entires_button": show_more_entires_button,
|
||||
"total_entries": total_entries,
|
||||
}
|
||||
return templates.TemplateResponse(request=request, name="feed.html", context=context)
|
||||
|
||||
else:
|
||||
start_after_entry = None
|
||||
|
||||
entries: typing.Iterable[Entry] = reader.get_entries(
|
||||
feed=clean_feed_url,
|
||||
starting_after=start_after_entry,
|
||||
limit=entries_per_page,
|
||||
)
|
||||
|
||||
entries = list(entries)
|
||||
|
||||
# Get the last entry.
|
||||
last_entry: Entry | None = None
|
||||
if entries:
|
||||
last_entry = entries[-1]
|
||||
|
||||
# Create the html for the entries.
|
||||
html: str = create_html_for_feed(entries)
|
||||
@ -549,47 +644,9 @@ async def get_feed(feed_url: str, request: Request, starting_after: str | None =
|
||||
"feed_counts": reader.get_feed_counts(feed=clean_feed_url),
|
||||
"html": html,
|
||||
"should_send_embed": should_send_embed,
|
||||
"show_more_button": True,
|
||||
}
|
||||
return templates.TemplateResponse(request=request, name="feed.html", context=context)
|
||||
|
||||
|
||||
@app.get("/feed_more", response_class=HTMLResponse)
|
||||
async def get_all_entries(feed_url: str, request: Request):
|
||||
"""Get a feed by URL and show more entries.
|
||||
|
||||
Args:
|
||||
feed_url: The feed to add.
|
||||
request: The request object.
|
||||
starting_after: The entry to start after. Used for pagination.
|
||||
|
||||
Returns:
|
||||
HTMLResponse: The feed page.
|
||||
"""
|
||||
clean_feed_url: str = urllib.parse.unquote(feed_url.strip())
|
||||
|
||||
feed: Feed = reader.get_feed(clean_feed_url)
|
||||
|
||||
# Get entries from the feed.
|
||||
entries: typing.Iterable[Entry] = reader.get_entries(feed=clean_feed_url, limit=200)
|
||||
|
||||
# Create the html for the entries.
|
||||
html: str = create_html_for_feed(entries)
|
||||
|
||||
try:
|
||||
should_send_embed: bool = bool(reader.get_tag(feed, "should_send_embed"))
|
||||
except TagNotFoundError:
|
||||
add_missing_tags(reader)
|
||||
should_send_embed: bool = bool(reader.get_tag(feed, "should_send_embed"))
|
||||
|
||||
context = {
|
||||
"request": request,
|
||||
"feed": feed,
|
||||
"entries": entries,
|
||||
"feed_counts": reader.get_feed_counts(feed=clean_feed_url),
|
||||
"html": html,
|
||||
"should_send_embed": should_send_embed,
|
||||
"show_more_button": False,
|
||||
"last_entry": last_entry,
|
||||
"show_more_entires_button": show_more_entires_button,
|
||||
"total_entries": total_entries,
|
||||
}
|
||||
return templates.TemplateResponse(request=request, name="feed.html", context=context)
|
||||
|
||||
|
@ -7,9 +7,9 @@ body {
|
||||
}
|
||||
|
||||
.text-muted {
|
||||
color: #888888 !important;
|
||||
color: #acabab !important;
|
||||
}
|
||||
|
||||
.form-text {
|
||||
color: #888888;
|
||||
color: #acabab;
|
||||
}
|
||||
|
@ -1,39 +1,32 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}
|
||||
| Add new feed
|
||||
| Add new feed
|
||||
{% endblock title %}
|
||||
{% block content %}
|
||||
<div class="p-2 border border-dark">
|
||||
<form action="/add" method="post">
|
||||
<!-- Feed URL -->
|
||||
<div class="row pb-2">
|
||||
<label for="feed_url" class="col-sm-2 col-form-label">RSS feed URL</label>
|
||||
<div class="col-sm-10">
|
||||
<input name="feed_url"
|
||||
type="text"
|
||||
class="form-control bg-dark border-dark text-muted"
|
||||
id="feed_url" />
|
||||
</div>
|
||||
<div class="p-2 border border-dark">
|
||||
<form action="/add" method="post">
|
||||
<!-- Feed URL -->
|
||||
<div class="row pb-2">
|
||||
<label for="feed_url" class="col-sm-2 col-form-label">Feed URL</label>
|
||||
<div class="col-sm-10">
|
||||
<input name="feed_url" type="text" class="form-control bg-dark border-dark text-muted" id="feed_url" />
|
||||
</div>
|
||||
<!-- Webhook dropdown -->
|
||||
<div class="row pb-2">
|
||||
<label for="webhook_dropdown" class="col-sm-2 col-form-label">Which webhook should we send entries to?</label>
|
||||
<div class="col-sm-10">
|
||||
<select class="col-auto form-select bg-dark border-dark text-muted"
|
||||
id="webhook_dropdown"
|
||||
name="webhook_dropdown">
|
||||
<option selected>Choose webhook...</option>
|
||||
{% for hook in webhooks %}<option value="{{ hook.name }}">{{- hook.name -}}</option>{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-text">
|
||||
You can add more webhooks <a class="text-muted" href="/add_webhook">here</a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Webhook dropdown -->
|
||||
<div class="row pb-2">
|
||||
<label for="webhook_dropdown" class="col-sm-2 col-form-label">Webhook</label>
|
||||
<div class="col-sm-10">
|
||||
<select class="col-auto form-select bg-dark border-dark text-muted" id="webhook_dropdown"
|
||||
name="webhook_dropdown">
|
||||
<option selected>Choose webhook...</option>
|
||||
{% for hook in webhooks %}<option value="{{ hook.name }}">{{- hook.name -}}</option>{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<!-- Submit button -->
|
||||
<div class="d-md-flex">
|
||||
<button class="btn btn-dark btn-sm">Add feed</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Submit button -->
|
||||
<div class="d-md-flex">
|
||||
<button class="btn btn-dark btn-sm">Add feed</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
@ -1,40 +1,34 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}
|
||||
| Add new webhook
|
||||
| Add new webhook
|
||||
{% endblock title %}
|
||||
{% block content %}
|
||||
<div class="p-2 border border-dark">
|
||||
<form action="/add_webhook" method="post">
|
||||
{# Webhook name #}
|
||||
<div class="row pb-2">
|
||||
<label for="webhook_name" class="col-sm-2 col-form-label">Webhook Name</label>
|
||||
<div class="col-sm-10">
|
||||
<input name="webhook_name"
|
||||
type="text"
|
||||
class="form-control bg-dark border-dark text-muted"
|
||||
id="webhook_name" />
|
||||
</div>
|
||||
<div class="p-2 border border-dark">
|
||||
<form action="/add_webhook" method="post">
|
||||
{# Webhook name #}
|
||||
<div class="row pb-2">
|
||||
<label for="webhook_name" class="col-sm-2 col-form-label">Webhook Name</label>
|
||||
<div class="col-sm-10">
|
||||
<input name="webhook_name" type="text" class="form-control bg-dark border-dark text-muted" id="webhook_name" />
|
||||
</div>
|
||||
{# Webhook URL #}
|
||||
<div class="row pb-2">
|
||||
<label for="webhook_url" class="col-sm-2 col-form-label">Webhook URL</label>
|
||||
<div class="col-sm-10">
|
||||
<input name="webhook_url"
|
||||
type="text"
|
||||
class="form-control bg-dark border-dark text-muted"
|
||||
id="webhook_url" />
|
||||
</div>
|
||||
<div class="form-text">
|
||||
You can append ?thread_id=THREAD_ID to the end
|
||||
of the URL to send messages to a thread. You can get
|
||||
the thread ID by right-clicking on the thread and
|
||||
Copy Thread ID.
|
||||
</div>
|
||||
</div>
|
||||
{# Webhook URL #}
|
||||
<div class="row pb-2">
|
||||
<label for="webhook_url" class="col-sm-2 col-form-label">Webhook URL</label>
|
||||
<div class="col-sm-10">
|
||||
<input name="webhook_url" type="text" class="form-control bg-dark border-dark text-muted" id="webhook_url" />
|
||||
</div>
|
||||
{# Submit button #}
|
||||
<div class="d-md-flex">
|
||||
<button class="btn btn-dark btn-sm">Add webhook</button>
|
||||
<div class="form-text">
|
||||
You can append ?thread_id=THREAD_ID to the end
|
||||
of the URL to send messages to a thread. You can get
|
||||
the thread ID by right-clicking on the thread and
|
||||
Copy Thread ID.
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{# Submit button #}
|
||||
<div class="d-md-flex">
|
||||
<button class="btn btn-dark btn-sm">Add webhook</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
@ -1,12 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="description"
|
||||
content="Stay updated with the latest news and events with our easy-to-use RSS bot. Never miss a message or announcement again with real-time notifications directly to your Discord server." />
|
||||
content="Stay updated with the latest news and events with our easy-to-use RSS bot. Never miss a message or announcement again with real-time notifications directly to your Discord server." />
|
||||
<meta name="keywords"
|
||||
content="discord, rss, bot, notifications, announcements, updates, real-time, server, messages, news, events, feed." />
|
||||
content="discord, rss, bot, notifications, announcements, updates, real-time, server, messages, news, events, feed." />
|
||||
<link href="/static/bootstrap.min.css" rel="stylesheet" />
|
||||
<link href="/static/styles.css" rel="stylesheet" />
|
||||
<link rel="icon" href="/static/favicon.ico" type="image/x-icon" />
|
||||
@ -17,11 +18,19 @@
|
||||
{% block head %}
|
||||
{% endblock head %}
|
||||
</head>
|
||||
|
||||
<body class="text-white-50">
|
||||
{% include "nav.html" %}
|
||||
<div class="p-2 mb-2">
|
||||
<div class="container-fluid">
|
||||
<div class="d-grid p-2">
|
||||
{% if messages %}
|
||||
<div class="alert alert-warning alert-dismissible fade show" role="alert">
|
||||
<pre>{{ messages }}</pre>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% block content %}
|
||||
{% endblock content %}
|
||||
<footer class="d-flex flex-wrap justify-content-between align-items-center py-3 my-4 border-top">
|
||||
@ -32,11 +41,11 @@
|
||||
<ul class="nav col-md-4 justify-content-end">
|
||||
<li class="nav-item">
|
||||
<a href="https://github.com/TheLovinator1/discord-rss-bot/issues"
|
||||
class="nav-link px-2 text-muted">Report an issue</a>
|
||||
class="nav-link px-2 text-muted">Report an issue</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="https://github.com/TheLovinator1/discord-rss-bot/issues"
|
||||
class="nav-link px-2 text-muted">Send feedback</a>
|
||||
class="nav-link px-2 text-muted">Send feedback</a>
|
||||
</li>
|
||||
</ul>
|
||||
</footer>
|
||||
@ -45,4 +54,5 @@
|
||||
</div>
|
||||
<script src="/static/bootstrap.min.js" defer></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
@ -1,67 +1,55 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}
|
||||
| Blacklist
|
||||
| Blacklist
|
||||
{% endblock title %}
|
||||
{% block content %}
|
||||
<div class="p-2 border border-dark">
|
||||
<form action="/blacklist" method="post">
|
||||
<!-- Feed URL -->
|
||||
<div class="row pb-2">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-text">
|
||||
<ul class="list-inline">
|
||||
<li>
|
||||
Comma separated list of words to blacklist. If a word is found in the
|
||||
corresponding blacklists, the feed will not be sent.
|
||||
</li>
|
||||
<li>Whitelist always takes precedence over blacklist. Leave empty to disable.</li>
|
||||
<li>Words are case-insensitive. No spaces should be used before or after the comma.</li>
|
||||
<li>
|
||||
Correct:
|
||||
<code>
|
||||
<div class="p-2 border border-dark">
|
||||
<form action="/blacklist" method="post">
|
||||
<!-- Feed URL -->
|
||||
<div class="row pb-2">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-text">
|
||||
<ul class="list-inline">
|
||||
<li>
|
||||
Comma separated list of words to blacklist. If a word is found in the
|
||||
corresponding blacklists, the feed will not be sent.
|
||||
</li>
|
||||
<li>Whitelist always takes precedence over blacklist. Leave empty to disable.</li>
|
||||
<li>Words are case-insensitive. No spaces should be used before or after the comma.</li>
|
||||
<li>
|
||||
Correct:
|
||||
<code>
|
||||
primogem,events,gameplay preview,special program
|
||||
</code>
|
||||
</li>
|
||||
<li>
|
||||
Wrong:
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
Wrong:
|
||||
<code>
|
||||
primogem, events, gameplay preview, special program
|
||||
</code>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<label for="blacklist_title" class="col-sm-6 col-form-label">Blacklist - Title</label>
|
||||
<input name="blacklist_title"
|
||||
type="text"
|
||||
class="form-control bg-dark border-dark text-muted"
|
||||
id="blacklist_title"
|
||||
value="{%- if blacklist_title -%}{{ blacklist_title }}{%- endif -%}" />
|
||||
<label for="blacklist_summary" class="col-sm-6 col-form-label">Blacklist - Summary</label>
|
||||
<input name="blacklist_summary"
|
||||
type="text"
|
||||
class="form-control bg-dark border-dark text-muted"
|
||||
id="blacklist_summary"
|
||||
value="{%- if blacklist_summary -%}{{ blacklist_summary }}{%- endif -%}" />
|
||||
<label for="blacklist_content" class="col-sm-6 col-form-label">Blacklist - Content</label>
|
||||
<input name="blacklist_content"
|
||||
type="text"
|
||||
class="form-control bg-dark border-dark text-muted"
|
||||
id="blacklist_content"
|
||||
value="{%- if blacklist_content -%}{{ blacklist_content }}{%- endif -%}" />
|
||||
<label for="blacklist_author" class="col-sm-6 col-form-label">Blacklist - Author</label>
|
||||
<input name="blacklist_author"
|
||||
type="text"
|
||||
class="form-control bg-dark border-dark text-muted"
|
||||
id="blacklist_author"
|
||||
value="{%- if blacklist_author -%}{{ blacklist_author }}{%- endif -%}" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<label for="blacklist_title" class="col-sm-6 col-form-label">Blacklist - Title</label>
|
||||
<input name="blacklist_title" type="text" class="form-control bg-dark border-dark text-muted"
|
||||
id="blacklist_title" value="{%- if blacklist_title -%}{{ blacklist_title }}{%- endif -%}" />
|
||||
<label for="blacklist_summary" class="col-sm-6 col-form-label">Blacklist - Summary</label>
|
||||
<input name="blacklist_summary" type="text" class="form-control bg-dark border-dark text-muted"
|
||||
id="blacklist_summary" value="{%- if blacklist_summary -%}{{ blacklist_summary }}{%- endif -%}" />
|
||||
<label for="blacklist_content" class="col-sm-6 col-form-label">Blacklist - Content</label>
|
||||
<input name="blacklist_content" type="text" class="form-control bg-dark border-dark text-muted"
|
||||
id="blacklist_content" value="{%- if blacklist_content -%}{{ blacklist_content }}{%- endif -%}" />
|
||||
<label for="blacklist_author" class="col-sm-6 col-form-label">Blacklist - Author</label>
|
||||
<input name="blacklist_author" type="text" class="form-control bg-dark border-dark text-muted"
|
||||
id="blacklist_author" value="{%- if blacklist_author -%}{{ blacklist_author }}{%- endif -%}" />
|
||||
</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 blacklist</button>
|
||||
</div>
|
||||
</form>
|
||||
</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 blacklist</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
@ -1,259 +1,252 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}
|
||||
| Custom message
|
||||
| Custom message
|
||||
{% endblock title %}
|
||||
{% block content %}
|
||||
<div class="p-2 border border-dark">
|
||||
<form action="/custom" method="post">
|
||||
<!-- Feed URL -->
|
||||
<div class="row pb-2">
|
||||
<div class="col-sm-12">
|
||||
<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>
|
||||
<div class="p-2 border border-dark">
|
||||
<form action="/custom" method="post">
|
||||
<!-- Feed URL -->
|
||||
<div class="row pb-2">
|
||||
<div class="col-sm-12">
|
||||
<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 }}
|
||||
{% endraw %}
|
||||
</code>{{ feed.author }}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ feed_added }}
|
||||
{% endraw %}
|
||||
</code>{{ feed.added }}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ feed_last_exception }}
|
||||
{% endraw %}
|
||||
</code>{{ feed.last_exception }}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ feed_last_updated }}
|
||||
{% endraw %}
|
||||
</code>{{ feed.last_updated }}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ feed_link }}
|
||||
{% endraw %}
|
||||
</code>{{ feed.link }}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ feed_subtitle }}
|
||||
{% endraw %}
|
||||
</code>{{ feed.subtitle }}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ feed_title }}
|
||||
{% endraw %}
|
||||
</code>{{ feed.title }}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ feed_updated }}
|
||||
{% endraw %}
|
||||
</code>{{ feed.updated }}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ feed_updates_enabled }}
|
||||
{% endraw %}
|
||||
</code>{{ feed.updates_enabled }}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ feed_url }}
|
||||
{% endraw %}
|
||||
</code>{{ feed.url }}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ feed_user_title }}
|
||||
{% endraw %}
|
||||
</code>{{ feed.user_title }}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ feed_version }}
|
||||
{% endraw %}
|
||||
</code>{{ feed.version }}
|
||||
</li>
|
||||
<br/>
|
||||
{% if entry %}
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<br />
|
||||
{% if entry %}
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ entry_added }}
|
||||
{% endraw %}
|
||||
</code>{{ entry.added }}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ entry_author }}
|
||||
{% endraw %}
|
||||
</code>{{ entry.author }}
|
||||
</li>
|
||||
{% if entry.content %}
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
{% if entry.content %}
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ entry_content }}
|
||||
{% endraw %}
|
||||
</code>{{ entry.content[0].value|discord_markdown }}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ entry_content_raw }}
|
||||
{% endraw %}
|
||||
</code>{{ entry.content[0].value }}
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ entry_id }}
|
||||
{% endraw %}
|
||||
</code>{{ entry.id }}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ entry_important }}
|
||||
{% endraw %}
|
||||
</code>{{ entry.important }}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ entry_link }}
|
||||
{% endraw %}
|
||||
</code>{{ entry.link }}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ entry_published }}
|
||||
{% endraw %}
|
||||
</code>{{ entry.published }}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ entry_read }}
|
||||
{% endraw %}
|
||||
</code>{{ entry.read }}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ entry_read_modified }}
|
||||
{% endraw %}
|
||||
</code>{{ entry.read_modified }}
|
||||
</li>
|
||||
{% if entry.summary %}
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
{% if entry.summary %}
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ entry_summary }}
|
||||
{% endraw %}
|
||||
</code>{{ entry.summary|discord_markdown }}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ entry_summary_raw }}
|
||||
{% endraw %}
|
||||
</code>{{ entry.summary }}
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ entry_title }}
|
||||
{% endraw %}
|
||||
</code>{{ entry.title }}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ entry_text }}
|
||||
{% endraw %}
|
||||
</code> Same as entry_content if it exists, otherwise entry_summary
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ entry_updated }}
|
||||
{% endraw %}
|
||||
</code>{{ entry.updated }}
|
||||
</li>
|
||||
<br/>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<br />
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ image_1 }}
|
||||
{% endraw %}
|
||||
</code>First image in the entry if it exists
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="list-inline">
|
||||
<li>Examples:</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="list-inline">
|
||||
<li>Examples:</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{ feed_title }}\n{{ entry_content }}
|
||||
{% endraw %}
|
||||
</code>
|
||||
</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="custom_message" class="col-sm-6 col-form-label">Message</label>
|
||||
<input name="custom_message"
|
||||
type="text"
|
||||
class="form-control bg-dark border-dark text-muted"
|
||||
id="custom_message"
|
||||
{% if custom_message %}
|
||||
value="{{- custom_message -}}"
|
||||
{% endif %}/>
|
||||
</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="custom_message" class="col-sm-6 col-form-label">Message</label>
|
||||
<input name="custom_message" type="text" class="form-control bg-dark border-dark text-muted"
|
||||
id="custom_message" {% if custom_message %} value="{{- custom_message -}}" {% endif %} />
|
||||
</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 message</button>
|
||||
</div>
|
||||
</form>
|
||||
</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 message</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
@ -1,15 +1,15 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}
|
||||
| Embed
|
||||
| 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/>
|
||||
<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 %}
|
||||
@ -94,218 +94,170 @@
|
||||
{% endraw %}
|
||||
</code>{{feed.version}}
|
||||
</li>
|
||||
<br/>
|
||||
<br />
|
||||
{% if entry %}
|
||||
<li>
|
||||
<code>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_added}}
|
||||
{% endraw %}
|
||||
</code>{{entry.added}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_author}}
|
||||
{% endraw %}
|
||||
</code>{{entry.author}}
|
||||
</li>
|
||||
{% if entry.content %}
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
{% if entry.content %}
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_content}}
|
||||
{% endraw %}
|
||||
</code>{{entry.content[0].value|discord_markdown}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_content_raw}}
|
||||
{% endraw %}
|
||||
</code>{{entry.content[0].value}}
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_id}}
|
||||
{% endraw %}
|
||||
</code>{{entry.id}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_important}}
|
||||
{% endraw %}
|
||||
</code>{{entry.important}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_link}}
|
||||
{% endraw %}
|
||||
</code>{{entry.link}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_published}}
|
||||
{% endraw %}
|
||||
</code>{{entry.published}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_read}}
|
||||
{% endraw %}
|
||||
</code>{{entry.read}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_read_modified}}
|
||||
{% endraw %}
|
||||
</code>{{entry.read_modified}}
|
||||
</li>
|
||||
{% if entry.summary %}
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
{% if entry.summary %}
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_summary}}
|
||||
{% endraw %}
|
||||
</code>{{entry.summary|discord_markdown}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_summary_raw}}
|
||||
{% endraw %}
|
||||
</code>{{entry.summary}}
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_title}}
|
||||
{% endraw %}
|
||||
</code>{{entry.title}}
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_text}}
|
||||
{% endraw %}
|
||||
</code> Same as entry_content if it exists, otherwise entry_summary
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{entry_updated}}
|
||||
{% endraw %}
|
||||
</code>{{entry.updated}}
|
||||
</li>
|
||||
<br/>
|
||||
<li>
|
||||
<code>
|
||||
</li>
|
||||
<br />
|
||||
<li>
|
||||
<code>
|
||||
{% raw %}
|
||||
{{image_1}}
|
||||
{% endraw %}
|
||||
</code>First image in the entry if it exists
|
||||
</li>
|
||||
</ul>
|
||||
</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.
|
||||
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>
|
||||
<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>
|
||||
<!-- 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>
|
||||
</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 %}
|
||||
|
@ -1,68 +1,84 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}
|
||||
| {{ feed.title }}
|
||||
| {{ feed.title }}
|
||||
{% endblock title %}
|
||||
{% block content %}
|
||||
<div class="p-2 mb-2 border border-dark">
|
||||
<!-- The feed title. -->
|
||||
<h2>
|
||||
<a class="text-muted text-decoration-none" href="{{ feed.url }}">{{ feed.title }}</a>
|
||||
</h2>
|
||||
{% if not feed.updates_enabled %}<span class="text-danger">Disabled</span>{% endif %}
|
||||
{% if feed.last_exception %}
|
||||
<h3 class="text-danger">{{ feed.last_exception.type_name }}:</h3>
|
||||
<code>{{ feed.last_exception.value_str }}</code>
|
||||
<pre><code>{{ feed.last_exception.traceback_str }}</code></pre>
|
||||
{% endif %}
|
||||
<form action="/remove" method="post">
|
||||
<button class="btn btn-danger btn-sm"
|
||||
name="feed_url"
|
||||
value="{{ feed.url }}"
|
||||
onclick="return confirm('Are you sure you want to delete this feed?')">Remove</button>
|
||||
</form>
|
||||
{% if not feed.updates_enabled %}
|
||||
<form action="/unpause" method="post">
|
||||
<button class="btn btn-dark btn-sm" name="feed_url" value="{{ feed.url }}">Unpause</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<form action="/pause" method="post">
|
||||
<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>
|
||||
<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>
|
||||
{{ html|safe }}
|
||||
</pre>
|
||||
{% if show_more_button %}
|
||||
<a class="btn btn-dark"
|
||||
href="/feed_more?feed_url={{ feed.url|encode_url }}">Show more (Note: This view is not optimized at all, so be ready to wait a while)</a>
|
||||
<div class="card mb-3 border border-dark p-3 text-light">
|
||||
<!-- Feed Title -->
|
||||
<h2>
|
||||
<a class="text-muted" href="{{ feed.url }}">{{ feed.title }}</a> ({{ total_entries }} entries)
|
||||
</h2>
|
||||
{% if not feed.updates_enabled %}
|
||||
<span class="badge bg-danger">Disabled</span>
|
||||
{% endif %}
|
||||
|
||||
{% if feed.last_exception %}
|
||||
<div class="mt-3">
|
||||
<h5 class="text-danger">{{ feed.last_exception.type_name }}:</h5>
|
||||
<code class="d-block">{{ feed.last_exception.value_str }}</code>
|
||||
<button class="btn btn-secondary btn-sm mt-2" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#exceptionDetails" aria-expanded="false" aria-controls="exceptionDetails">
|
||||
Show Traceback
|
||||
</button>
|
||||
<div class="collapse" id="exceptionDetails">
|
||||
<pre><code>{{ feed.last_exception.traceback_str }}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Feed Actions -->
|
||||
<div class="mt-3 d-flex flex-wrap gap-2">
|
||||
<form action="/remove" method="post" class="d-inline">
|
||||
<button class="btn btn-danger btn-sm" name="feed_url" value="{{ feed.url }}"
|
||||
onclick="return confirm('Are you sure you want to delete this feed?')">Remove</button>
|
||||
</form>
|
||||
|
||||
{% if not feed.updates_enabled %}
|
||||
<form action="/unpause" method="post" class="d-inline">
|
||||
<button class="btn btn-secondary btn-sm" name="feed_url" value="{{ feed.url }}">Unpause</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<form action="/pause" method="post" class="d-inline">
|
||||
<button class="btn btn-danger btn-sm" name="feed_url" value="{{ feed.url }}">Pause</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
{% if should_send_embed %}
|
||||
<form action="/use_text" method="post" class="d-inline">
|
||||
<button class="btn btn-dark btn-sm" name="feed_url" value="{{ feed.url }}">
|
||||
Send text message instead of embed
|
||||
</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<form action="/use_embed" method="post" class="d-inline">
|
||||
<button class="btn btn-dark btn-sm" name="feed_url" value="{{ feed.url }}">
|
||||
Send embed instead of text message
|
||||
</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Additional Links -->
|
||||
<div class="mt-3">
|
||||
<a class="text-muted d-block" href="/whitelist?feed_url={{ feed.url|encode_url }}">Whitelist</a>
|
||||
<a class="text-muted d-block" href="/blacklist?feed_url={{ feed.url|encode_url }}">Blacklist</a>
|
||||
<a class="text-muted d-block" href="/custom?feed_url={{ feed.url|encode_url }}">
|
||||
Customize message {% if not should_send_embed %}(Currently active){% endif %}
|
||||
</a>
|
||||
<a class="text-muted d-block" href="/embed?feed_url={{ feed.url|encode_url }}">
|
||||
Customize embed {% if should_send_embed %}(Currently active){% endif %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Rendered HTML content #}
|
||||
<pre>{{ html|safe }}</pre>
|
||||
|
||||
{% if show_more_entires_button %}
|
||||
<a class="btn btn-dark mt-3"
|
||||
href="/feed?feed_url={{ feed.url|encode_url }}&starting_after={{ last_entry.id|encode_url }}">
|
||||
Show more entries
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
{% endblock content %}
|
||||
|
@ -1,88 +1,92 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<!-- List all feeds -->
|
||||
<ul>
|
||||
<!-- Check if any feeds -->
|
||||
{% if feeds %}
|
||||
<p>
|
||||
{{ feed_count.total }} feed{{'s' if feed_count.total > 1 else "" }}
|
||||
<!-- How many broken feeds -->
|
||||
<!-- Make broken feed text red if true. -->
|
||||
{% if feed_count.broken %}
|
||||
- <span class="text-danger">{{ feed_count.broken }} broken</span>
|
||||
{% else %}
|
||||
- {{ feed_count.broken }} broken
|
||||
{% endif %}
|
||||
<!-- How many enabled feeds -->
|
||||
<!-- Make amount of enabled feeds yellow if some are disabled. -->
|
||||
{% if feed_count.total != feed_count.updates_enabled %}
|
||||
- <span class="text-warning">{{ feed_count.updates_enabled }} enabled</span>
|
||||
{% else %}
|
||||
- {{ feed_count.updates_enabled }} enabled
|
||||
{% endif %}
|
||||
<!-- How many entries -->
|
||||
- {{ entry_count.total }} entries
|
||||
<abbr title="Average entries per day for the past 1, 3 and 12 months">
|
||||
({{ entry_count.averages[0]|round(1) }},
|
||||
{{ entry_count.averages[1]|round(1) }},
|
||||
{{ entry_count.averages[2]|round(1) }})
|
||||
</abbr>
|
||||
</p>
|
||||
<!-- Loop through the webhooks and add the feeds connected to them. -->
|
||||
{% for hook_from_context in webhooks %}
|
||||
<div class="p-2 mb-2 border border-dark">
|
||||
<ul class="list-group">
|
||||
<h1 class="h5">
|
||||
<a class="text-muted" href="/webhooks">{{ hook_from_context.name }}</a>
|
||||
</h1>
|
||||
{% for feed_webhook in feeds %}
|
||||
{% set feed = feed_webhook["feed"] %}
|
||||
{% set hook_from_feed = feed_webhook["webhook"] %}
|
||||
{% if hook_from_context.url == hook_from_feed %}
|
||||
<div>
|
||||
<a class="text-muted" href="/feed?feed_url={{ feed.url|encode_url }}">{{ feed.url }}</a>
|
||||
{% if not feed.updates_enabled %}<span class="text-warning">Disabled</span>{% endif %}
|
||||
{% if feed.last_exception %}<span class="text-danger">({{ feed.last_exception.value_str }})</span>{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<!-- List all feeds -->
|
||||
<ul>
|
||||
<!-- Check if any feeds -->
|
||||
{% if feeds %}
|
||||
<p>
|
||||
{{ feed_count.total }} feed{{'s' if feed_count.total > 1 else "" }}
|
||||
<!-- How many broken feeds -->
|
||||
<!-- Make broken feed text red if true. -->
|
||||
{% if feed_count.broken %}
|
||||
- <span class="text-danger">{{ feed_count.broken }} broken</span>
|
||||
{% else %}
|
||||
<p>
|
||||
Hello there!
|
||||
</br>
|
||||
You need to add a webhook to get started and then add a feed. You can find both options in the menu above.
|
||||
</br>
|
||||
</br>
|
||||
If you have any questions or suggestions, feel free to contact me on <a class="text-muted" href="mailto:tlovinator@gmail.com">tlovinator@gmail.com</a> or TheLovinator#9276 on Discord.
|
||||
</br>
|
||||
Thanks!
|
||||
</p>
|
||||
{% endif %}
|
||||
<!-- Show feeds without webhooks -->
|
||||
{% if broken_feeds %}
|
||||
- {{ feed_count.broken }} broken
|
||||
{% endif %}
|
||||
<!-- How many enabled feeds -->
|
||||
<!-- Make amount of enabled feeds yellow if some are disabled. -->
|
||||
{% if feed_count.total != feed_count.updates_enabled %}
|
||||
- <span class="text-warning">{{ feed_count.updates_enabled }} enabled</span>
|
||||
{% else %}
|
||||
- {{ feed_count.updates_enabled }} enabled
|
||||
{% endif %}
|
||||
<!-- How many entries -->
|
||||
- {{ entry_count.total }} entries
|
||||
<abbr title="Average entries per day for the past 1, 3 and 12 months">
|
||||
({{ entry_count.averages[0]|round(1) }},
|
||||
{{ entry_count.averages[1]|round(1) }},
|
||||
{{ entry_count.averages[2]|round(1) }})
|
||||
</abbr>
|
||||
</p>
|
||||
<!-- Loop through the webhooks and add the feeds connected to them. -->
|
||||
{% for hook_from_context in webhooks %}
|
||||
<div class="p-2 mb-2 border border-dark">
|
||||
<h2 class="h5">
|
||||
<a class="text-muted" href="/webhooks">{{ hook_from_context.name }}</a>
|
||||
</h2>
|
||||
<ul class="list-group">
|
||||
{% for feed_webhook in feeds %}
|
||||
{% set feed = feed_webhook["feed"] %}
|
||||
{% set hook_from_feed = feed_webhook["webhook"] %}
|
||||
{% if hook_from_context.url == hook_from_feed %}
|
||||
<div>
|
||||
<a class="text-muted" href="/feed?feed_url={{ feed.url|encode_url }}">{{ feed.url }}</a>
|
||||
{% if not feed.updates_enabled %}<span class="text-warning">Disabled</span>{% endif %}
|
||||
{% if feed.last_exception %}<span
|
||||
class="text-danger">({{ feed.last_exception.value_str }})</span>{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p>
|
||||
Hello there!
|
||||
<br>
|
||||
You need to add a webhook <a class="text-muted" href="/add_webhook">here</a> to get started. After that, you can
|
||||
add feeds <a class="text-muted" href="/add">here</a>. You can find both of these links in the navigation bar
|
||||
above.
|
||||
<br>
|
||||
<br>
|
||||
If you have any questions or suggestions, feel free to contact me on <a class="text-muted"
|
||||
href="mailto:tlovinator@gmail.com">tlovinator@gmail.com</a> or TheLovinator#9276 on Discord.
|
||||
<br>
|
||||
<br>
|
||||
Thanks!
|
||||
</p>
|
||||
{% endif %}
|
||||
<!-- Show feeds without webhooks -->
|
||||
{% if broken_feeds %}
|
||||
<div class="p-2 mb-2 border border-dark">
|
||||
<ul class="list-group text-danger">
|
||||
Feeds without webhook:
|
||||
{% for broken_feed in broken_feeds %}
|
||||
<a class="text-muted"
|
||||
href="/feed?feed_url={{ broken_feed.url|encode_url }}">{{ broken_feed.url }}</a>
|
||||
<a class="text-muted" href="/feed?feed_url={{ broken_feed.url|encode_url }}">{{ broken_feed.url }}</a>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
<!-- Show feeds that has no attached webhook -->
|
||||
{% if feeds_without_attached_webhook %}
|
||||
{% endif %}
|
||||
<!-- Show feeds that has no attached webhook -->
|
||||
{% if feeds_without_attached_webhook %}
|
||||
<div class="p-2 mb-2 border border-dark">
|
||||
<ul class="list-group text-danger">
|
||||
Feeds without attached webhook:
|
||||
{% for feed in feeds_without_attached_webhook %}
|
||||
<a class="text-muted" href="/feed?feed_url={{ feed.url|encode_url }}">{{ feed.url }}</a>
|
||||
<a class="text-muted" href="/feed?feed_url={{ feed.url|encode_url }}">{{ feed.url }}</a>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
{% endblock content %}
|
||||
|
@ -1,9 +1,6 @@
|
||||
<nav class="navbar navbar-expand-md navbar-dark p-2 mb-3 border-bottom border-warning">
|
||||
<div class="container-fluid">
|
||||
<button class="navbar-toggler ms-auto"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#collapseNavbar">
|
||||
<button class="navbar-toggler ms-auto" type="button" data-bs-toggle="collapse" data-bs-target="#collapseNavbar">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="navbar-collapse collapse" id="collapseNavbar">
|
||||
@ -22,10 +19,8 @@
|
||||
</ul>
|
||||
{# Search #}
|
||||
<form action="/search" method="get" class="ms-auto w-50 input-group">
|
||||
<input name="query"
|
||||
class="form-control bg-dark border-dark text-muted"
|
||||
type="search"
|
||||
placeholder="Search" />
|
||||
<input name="query" class="form-control bg-dark border-dark text-muted" type="search"
|
||||
placeholder="Search" />
|
||||
</form>
|
||||
{# Donate button #}
|
||||
<ul class="navbar-nav ms-auto">
|
||||
|
@ -1,10 +1,10 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}
|
||||
| Search
|
||||
| Search
|
||||
{% endblock title %}
|
||||
{% block content %}
|
||||
<div class="p-2 border border-dark text-muted">
|
||||
Your search for "{{- query -}}" returned {{- search_amount.total -}} results.
|
||||
</div>
|
||||
{{- search_html | safe -}}
|
||||
<div class="p-2 border border-dark text-muted">
|
||||
Your search for "{{- query -}}" returned {{- search_amount.total -}} results.
|
||||
</div>
|
||||
{{- search_html | safe -}}
|
||||
{% endblock content %}
|
||||
|
@ -1,48 +1,55 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}
|
||||
| Webhooks
|
||||
| Webhooks
|
||||
{% endblock title %}
|
||||
{% block content %}
|
||||
{# List all available webhooks #}
|
||||
<h3>Available webhooks</h3>
|
||||
<ul class="list-inline">
|
||||
<a class="btn btn-primary" href="/add_webhook">Add new</a>
|
||||
<br />
|
||||
{% for hook in hooks_with_data %}
|
||||
<div class="p-2 border border-dark text-muted">
|
||||
<h3>{{ hook.custom_name }}</h3>
|
||||
<div class="container my-4 text-light">
|
||||
{% for hook in hooks_with_data %}
|
||||
<div class="border border-dark mb-4 shadow-sm p-3">
|
||||
<div class="text-muted">
|
||||
<h4>{{ hook.custom_name }}</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li>
|
||||
<strong>Name</strong>: {{ hook.name }}
|
||||
<strong>
|
||||
<abbr title="Name configured in Discord">
|
||||
Discord name:</strong> {{ hook.name }}
|
||||
</abbr>
|
||||
</li>
|
||||
<li>
|
||||
<strong>Webhook URL</strong>: <a class="text-muted" href="{{ hook.url }}">{{ hook.url }}</a>
|
||||
<strong>Webhook:</strong>
|
||||
<a class="text-muted"
|
||||
href="{{ hook.url }}">{{ hook.url | replace("https://discord.com/api/webhooks", "") }}</a>
|
||||
</li>
|
||||
<br />
|
||||
<form action="/modify_webhook" method="post">
|
||||
<input type="hidden" name="old_hook" value="{{- hook.url -}}" />
|
||||
<div class="row pb-2">
|
||||
<label for="new_hook" class="col-sm-1 col-form-label">Modify webhook</label>
|
||||
<div class="col-sm-9">
|
||||
<input name="new_hook"
|
||||
type="text"
|
||||
class="form-control bg-dark border-dark text-muted"
|
||||
id="new_hook" />
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary col-sm-1 ">Modify</button>
|
||||
<div class="form-text">
|
||||
You can append ?thread_id=THREAD_ID to the end
|
||||
of the URL to send messages to a thread. You can get
|
||||
the thread ID by right-clicking on the thread and
|
||||
Copy Thread ID.
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<form action="/delete_webhook" method="post">
|
||||
<input type="hidden" name="webhook_url" value="{{- hook.url -}}" />
|
||||
<button type="submit" class="btn btn-danger">Delete</button>
|
||||
</form>
|
||||
</div>
|
||||
<br />
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</ul>
|
||||
<hr>
|
||||
<form action="/modify_webhook" method="post" class="row g-3">
|
||||
<input type="hidden" name="old_hook" value="{{ hook.url }}" />
|
||||
<div class="col-md-8">
|
||||
<label for="new_hook" class="form-label">Modify Webhook</label>
|
||||
<input type="text" name="new_hook" id="new_hook" class="form-control border text-muted bg-dark"
|
||||
placeholder="Enter new webhook URL" />
|
||||
|
||||
</div>
|
||||
<div class="col-md-4 d-flex align-items-end">
|
||||
<button type="submit" class="btn btn-primary w-100">Modify</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mt-2">
|
||||
<form action="/delete_webhook" method="post">
|
||||
<input type="hidden" name="webhook_url" value="{{ hook.url }}" />
|
||||
<button type="submit" class="btn btn-danger"
|
||||
onclick="return confirm('Are you sure you want to delete this webhook?');">Delete</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="border border-dark p-3">
|
||||
You can append <code>?thread_id=THREAD_ID</code> to the URL to send messages to a thread.
|
||||
</div>
|
||||
<br>
|
||||
<div class="text-end">
|
||||
<a class="btn btn-primary mb-3" href="/add_webhook">Add New Webhook</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
@ -1,67 +1,55 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}
|
||||
| Blacklist
|
||||
| Blacklist
|
||||
{% endblock title %}
|
||||
{% block content %}
|
||||
<div class="p-2 border border-dark">
|
||||
<form action="/whitelist" method="post">
|
||||
<!-- Feed URL -->
|
||||
<div class="row pb-2">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-text">
|
||||
<ul class="list-inline">
|
||||
<li>
|
||||
Comma separated list of words to whitelist. Only send message to
|
||||
Discord if one of these words are present in the corresponding fields.
|
||||
</li>
|
||||
<li>Whitelist always takes precedence over blacklist. Leave empty to disable.</li>
|
||||
<li>Words are case-insensitive. No spaces should be used before or after the comma.</li>
|
||||
<li>
|
||||
Correct:
|
||||
<code>
|
||||
<div class="p-2 border border-dark">
|
||||
<form action="/whitelist" method="post">
|
||||
<!-- Feed URL -->
|
||||
<div class="row pb-2">
|
||||
<div class="col-sm-12">
|
||||
<div class="form-text">
|
||||
<ul class="list-inline">
|
||||
<li>
|
||||
Comma separated list of words to whitelist. Only send message to
|
||||
Discord if one of these words are present in the corresponding fields.
|
||||
</li>
|
||||
<li>Whitelist always takes precedence over blacklist. Leave empty to disable.</li>
|
||||
<li>Words are case-insensitive. No spaces should be used before or after the comma.</li>
|
||||
<li>
|
||||
Correct:
|
||||
<code>
|
||||
primogem,events,gameplay preview,special program
|
||||
</code>
|
||||
</li>
|
||||
<li>
|
||||
Wrong:
|
||||
<code>
|
||||
</li>
|
||||
<li>
|
||||
Wrong:
|
||||
<code>
|
||||
primogem, events, gameplay preview, special program
|
||||
</code>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<label for="whitelist_title" class="col-sm-6 col-form-label">Whitelist - Title</label>
|
||||
<input name="whitelist_title"
|
||||
type="text"
|
||||
class="form-control bg-dark border-dark text-muted"
|
||||
id="whitelist_title"
|
||||
value="{%- if whitelist_title -%}{{ whitelist_title }} {%- endif -%}" />
|
||||
<label for="whitelist_summary" class="col-sm-6 col-form-label">Whitelist - Summary</label>
|
||||
<input name="whitelist_summary"
|
||||
type="text"
|
||||
class="form-control bg-dark border-dark text-muted"
|
||||
id="whitelist_summary"
|
||||
value="{%- if whitelist_summary -%}{{ whitelist_summary }}{%- endif -%}" />
|
||||
<label for="whitelist_content" class="col-sm-6 col-form-label">Whitelist - Content</label>
|
||||
<input name="whitelist_content"
|
||||
type="text"
|
||||
class="form-control bg-dark border-dark text-muted"
|
||||
id="whitelist_content"
|
||||
value="{%- if whitelist_content -%}{{ whitelist_content }}{%- endif -%}" />
|
||||
<label for="whitelist_author" class="col-sm-6 col-form-label">Whitelist - Author</label>
|
||||
<input name="whitelist_author"
|
||||
type="text"
|
||||
class="form-control bg-dark border-dark text-muted"
|
||||
id="whitelist_author"
|
||||
value="{%- if whitelist_author -%} {{ whitelist_author }} {%- endif -%}" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<label for="whitelist_title" class="col-sm-6 col-form-label">Whitelist - Title</label>
|
||||
<input name="whitelist_title" type="text" class="form-control bg-dark border-dark text-muted"
|
||||
id="whitelist_title" value="{%- if whitelist_title -%}{{ whitelist_title }} {%- endif -%}" />
|
||||
<label for="whitelist_summary" class="col-sm-6 col-form-label">Whitelist - Summary</label>
|
||||
<input name="whitelist_summary" type="text" class="form-control bg-dark border-dark text-muted"
|
||||
id="whitelist_summary" value="{%- if whitelist_summary -%}{{ whitelist_summary }}{%- endif -%}" />
|
||||
<label for="whitelist_content" class="col-sm-6 col-form-label">Whitelist - Content</label>
|
||||
<input name="whitelist_content" type="text" class="form-control bg-dark border-dark text-muted"
|
||||
id="whitelist_content" value="{%- if whitelist_content -%}{{ whitelist_content }}{%- endif -%}" />
|
||||
<label for="whitelist_author" class="col-sm-6 col-form-label">Whitelist - Author</label>
|
||||
<input name="whitelist_author" type="text" class="form-control bg-dark border-dark text-muted"
|
||||
id="whitelist_author" value="{%- if whitelist_author -%} {{ whitelist_author }} {%- endif -%}" />
|
||||
</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 whitelist</button>
|
||||
</div>
|
||||
</form>
|
||||
</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 whitelist</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
@ -1,74 +0,0 @@
|
||||
from typing import cast
|
||||
|
||||
from fastapi import HTTPException
|
||||
from reader import Reader
|
||||
|
||||
from discord_rss_bot.missing_tags import add_missing_tags
|
||||
|
||||
|
||||
def add_webhook(reader: Reader, webhook_name: str, webhook_url: str) -> None:
|
||||
"""Add new webhook.
|
||||
|
||||
Args:
|
||||
reader: The Reader to use
|
||||
webhook_name: The name of the webhook, this will be shown on the webpage
|
||||
webhook_url: The webhook URL to send entries to
|
||||
|
||||
Raises:
|
||||
HTTPException: This is raised when the webhook already exists
|
||||
"""
|
||||
# Get current webhooks from the database if they exist otherwise use an empty list.
|
||||
webhooks = list(reader.get_tag((), "webhooks", []))
|
||||
|
||||
# Webhooks are stored as a list of dictionaries.
|
||||
# Example: [{"name": "webhook_name", "url": "webhook_url"}]
|
||||
webhooks = cast(list[dict[str, str]], webhooks)
|
||||
|
||||
# Only add the webhook if it doesn't already exist.
|
||||
if all(webhook["name"] != webhook_name.strip() for webhook in webhooks):
|
||||
# Add the new webhook to the list of webhooks.
|
||||
webhooks.append({"name": webhook_name.strip(), "url": webhook_url.strip()})
|
||||
|
||||
# Add our new list of webhooks to the database.
|
||||
reader.set_tag((), "webhooks", webhooks) # type: ignore
|
||||
|
||||
add_missing_tags(reader)
|
||||
return
|
||||
|
||||
# TODO(TheLovinator): Show this error on the page.
|
||||
# TODO(TheLovinator): Replace HTTPException with a custom exception.
|
||||
raise HTTPException(status_code=409, detail="Webhook already exists")
|
||||
|
||||
|
||||
def remove_webhook(reader: Reader, webhook_url: str) -> None:
|
||||
"""Remove webhook.
|
||||
|
||||
Args:
|
||||
reader (Reader): The Reader to use
|
||||
webhook_url (str): The webhook URL to remove
|
||||
|
||||
Raises:
|
||||
HTTPException: If webhook could not be deleted
|
||||
HTTPException: Webhook not found
|
||||
"""
|
||||
# TODO(TheLovinator): Replace HTTPException with a custom exception for both of these.
|
||||
# Get current webhooks from the database if they exist otherwise use an empty list.
|
||||
webhooks = list(reader.get_tag((), "webhooks", []))
|
||||
|
||||
# Webhooks are stored as a list of dictionaries.
|
||||
# Example: [{"name": "webhook_name", "url": "webhook_url"}]
|
||||
webhooks = cast(list[dict[str, str]], webhooks)
|
||||
|
||||
# Only add the webhook if it doesn't already exist.
|
||||
webhooks_to_remove = [webhook for webhook in webhooks if webhook["url"] in webhook_url.strip()]
|
||||
|
||||
# Remove the webhooks outside of the loop.
|
||||
for webhook in webhooks_to_remove:
|
||||
webhooks.remove(webhook)
|
||||
|
||||
# Check if any webhooks were removed.
|
||||
if any(webhook in webhooks for webhook in webhooks_to_remove):
|
||||
raise HTTPException(status_code=500, detail="Webhook could not be deleted")
|
||||
|
||||
# Add our new list of webhooks to the database.
|
||||
reader.set_tag((), "webhooks", webhooks) # type: ignore
|
Reference in New Issue
Block a user