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

This commit is contained in:
2026-03-21 21:03:08 +01:00
parent 6ec1df4f78
commit cbd1947acb
2 changed files with 69 additions and 19 deletions

View 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

View File

@@ -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: