feat: Implement a Discord bot for RSS feed checking with slash commands and add a Gitea Actions workflow for Docker image build and push.
Some checks failed
Build and Push Docker Image / build-and-push (push) Failing after 16s
Some checks failed
Build and Push Docker Image / build-and-push (push) Failing after 16s
This commit is contained in:
37
.gitea/workflows/build.yml
Normal file
37
.gitea/workflows/build.yml
Normal file
@@ -0,0 +1,37 @@
|
||||
name: Build and Push Docker Image
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
env:
|
||||
REGISTRY: git.out.jafre.li
|
||||
IMAGE_NAME: jafreli/updater
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Login to Gitea Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ var.REGISTRY_USER }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
|
||||
- name: Extract version from tag
|
||||
id: version
|
||||
run: echo "VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: |
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
||||
51
src/bot.py
51
src/bot.py
@@ -2,6 +2,8 @@
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import re
|
||||
from html import unescape
|
||||
|
||||
import discord
|
||||
from discord import app_commands
|
||||
@@ -12,6 +14,28 @@ from .feed_checker import check_feeds, initialize_feed
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Regex to strip HTML tags
|
||||
_HTML_TAG_RE = re.compile(r"<[^>]+>")
|
||||
|
||||
|
||||
def clean_html(text: str) -> str:
|
||||
"""Strip HTML tags and decode HTML entities."""
|
||||
text = _HTML_TAG_RE.sub("", text)
|
||||
return unescape(text).strip()
|
||||
|
||||
|
||||
def _build_embed(title: str, link: str, feed_url: str) -> discord.Embed:
|
||||
"""Build a nice Discord embed for an RSS entry."""
|
||||
title = clean_html(title)
|
||||
|
||||
embed = discord.Embed(
|
||||
title=title,
|
||||
url=link if link else None,
|
||||
color=0x2B82D4,
|
||||
)
|
||||
embed.set_footer(text=f"📰 {feed_url}")
|
||||
return embed
|
||||
|
||||
|
||||
class RSSBot(discord.Client):
|
||||
"""Discord client with RSS feed monitoring."""
|
||||
@@ -138,18 +162,13 @@ class RSSBot(discord.Client):
|
||||
logger.exception("Could not fetch target channel")
|
||||
return
|
||||
|
||||
title = entry["title"]
|
||||
link = entry["link"]
|
||||
if link:
|
||||
message = f"📢 **{title}**\n{link}"
|
||||
else:
|
||||
message = f"📢 **{title}**"
|
||||
embed = _build_embed(entry["title"], entry["link"], url)
|
||||
|
||||
try:
|
||||
await channel.send(message)
|
||||
logger.info("Posted newest entry from new feed: %s", title)
|
||||
await channel.send(embed=embed)
|
||||
logger.info("Posted newest entry from new feed: %s", entry["title"])
|
||||
except Exception:
|
||||
logger.exception("Failed to post entry: %s", title)
|
||||
logger.exception("Failed to post entry: %s", entry["title"])
|
||||
|
||||
async def _check_and_post(self) -> None:
|
||||
"""Check feeds and post new entries to the target channel."""
|
||||
@@ -164,19 +183,13 @@ class RSSBot(discord.Client):
|
||||
new_entries = check_feeds()
|
||||
|
||||
for entry in new_entries:
|
||||
title = entry["title"]
|
||||
link = entry["link"]
|
||||
|
||||
if link:
|
||||
message = f"📢 **{title}**\n{link}"
|
||||
else:
|
||||
message = f"📢 **{title}**"
|
||||
embed = _build_embed(entry["title"], entry["link"], entry["feed_url"])
|
||||
|
||||
try:
|
||||
await channel.send(message)
|
||||
logger.info("Posted: %s", title)
|
||||
await channel.send(embed=embed)
|
||||
logger.info("Posted: %s", entry["title"])
|
||||
except Exception:
|
||||
logger.exception("Failed to post entry: %s", title)
|
||||
logger.exception("Failed to post entry: %s", entry["title"])
|
||||
|
||||
@tasks.loop(seconds=300) # default, overridden in on_ready
|
||||
async def check_loop(self) -> None:
|
||||
|
||||
Reference in New Issue
Block a user