Compare commits
2 Commits
7fe2a1de00
...
3e1255ccdc
Author | SHA1 | Date | |
---|---|---|---|
3e1255ccdc
|
|||
3bb33ca379
|
@ -5,6 +5,8 @@ import logging
|
||||
import requests
|
||||
import threading
|
||||
import smtplib
|
||||
import re
|
||||
import unicodedata
|
||||
from bs4 import BeautifulSoup
|
||||
from io import BytesIO
|
||||
from mastodon import Mastodon
|
||||
@ -61,6 +63,45 @@ def should_send_email(on_success: bool):
|
||||
return (mode == "all") or (mode == "errors" and not on_success)
|
||||
|
||||
|
||||
def extract_facets_utf8(text: str):
|
||||
import re
|
||||
facets = []
|
||||
def get_byte_range(char_start, char_end):
|
||||
byte_start = len(text[:char_start].encode("utf-8"))
|
||||
byte_end = len(text[:char_end].encode("utf-8"))
|
||||
return byte_start, byte_end
|
||||
|
||||
# Hashtags
|
||||
for match in re.finditer(r"#(\w+)", text):
|
||||
tag = match.group(1)
|
||||
char_start, char_end = match.span()
|
||||
byte_start, byte_end = get_byte_range(char_start, char_end)
|
||||
|
||||
facets.append({
|
||||
"index": {"byteStart": byte_start, "byteEnd": byte_end},
|
||||
"features": [{
|
||||
"$type": "app.bsky.richtext.facet#tag",
|
||||
"tag": tag
|
||||
}]
|
||||
})
|
||||
|
||||
# Links
|
||||
for match in re.finditer(r"https?://[^\s]+", text):
|
||||
url = match.group(0)
|
||||
char_start, char_end = match.span()
|
||||
byte_start, byte_end = get_byte_range(char_start, char_end)
|
||||
|
||||
facets.append({
|
||||
"index": {"byteStart": byte_start, "byteEnd": byte_end},
|
||||
"features": [{
|
||||
"$type": "app.bsky.richtext.facet#link",
|
||||
"uri": url
|
||||
}]
|
||||
})
|
||||
|
||||
return facets
|
||||
|
||||
|
||||
def generate_email_html(status: str, title: str, link: str, error_message: str = None) -> str:
|
||||
color = "#2e7d32" if status == "success" else "#d32f2f"
|
||||
bg_color = "#f5f5f5" if status == "success" else "#fff3f3"
|
||||
@ -161,15 +202,21 @@ def fetch_og_data(url):
|
||||
return None, None
|
||||
|
||||
|
||||
def post_to_bluesky(message, link):
|
||||
def post_to_bluesky(title, link, tags):
|
||||
client = Client()
|
||||
client.login(BSKY_HANDLE, BSKY_PASSWORD)
|
||||
|
||||
title, image_url = fetch_og_data(link)
|
||||
text = title or message
|
||||
hashtags = " ".join(f"#{tag}" for tag in tags) if tags else ""
|
||||
message = f"{title}\n\n{link}"
|
||||
if hashtags:
|
||||
message += f"\n\n{hashtags}"
|
||||
|
||||
if title and image_url:
|
||||
facets = extract_facets_utf8(message) # <-- NEU
|
||||
|
||||
# Versuche OG-Vorschau
|
||||
try:
|
||||
og_title, image_url = fetch_og_data(link)
|
||||
if og_title and image_url:
|
||||
embed = {
|
||||
"$type": "app.bsky.embed.external",
|
||||
"external": {
|
||||
@ -190,16 +237,18 @@ def post_to_bluesky(message, link):
|
||||
blob = client.upload_blob(BytesIO(img_resp.content))
|
||||
embed["external"]["thumb"] = blob.blob
|
||||
|
||||
client.send_post(text=text, embed=embed)
|
||||
client.send_post(text=message, embed=embed, facets=facets) # <-- facets hier
|
||||
logger.info(f"✅ Posted to Bluesky with preview.")
|
||||
return
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Error uploading preview to Bluesky: {e}")
|
||||
|
||||
client.send_post(f"{text}\n{link}")
|
||||
# Fallback: Nur Text, aber mit Facets
|
||||
client.send_post(text=message, facets=facets) # <-- facets hier
|
||||
logger.info(f"💡 Posted to Bluesky without preview.")
|
||||
|
||||
|
||||
|
||||
def extract_post_date(entry):
|
||||
date_fields = [
|
||||
entry.get("published"),
|
||||
@ -247,9 +296,19 @@ def main():
|
||||
title = entry.get("title", "").strip()
|
||||
link = entry.get("link", "").strip()
|
||||
|
||||
def sanitize_tag(tag):
|
||||
tag = tag.lower()
|
||||
tag = unicodedata.normalize("NFKD", tag).encode("ascii", "ignore").decode("ascii")
|
||||
tag = re.sub(r"\W+", "", tag)
|
||||
return tag
|
||||
|
||||
tags = []
|
||||
if "tags" in entry:
|
||||
tags = [tag["term"] for tag in entry.tags if "term" in tag]
|
||||
raw_tags = [
|
||||
tag.get("term") if isinstance(tag, dict) else getattr(tag, "term", None)
|
||||
for tag in entry.tags
|
||||
]
|
||||
tags = [sanitize_tag(t) for t in raw_tags if t]
|
||||
|
||||
if tags:
|
||||
hashtags = " ".join(f"#{tag}" for tag in tags)
|
||||
@ -265,7 +324,7 @@ def main():
|
||||
time.sleep(2)
|
||||
|
||||
if POST_TARGETS in ("bluesky", "both"):
|
||||
post_to_bluesky(f"{title}\n{link}", link)
|
||||
post_to_bluesky(title, link, tags)
|
||||
|
||||
save_seen_id(post_id)
|
||||
logger.info(f"✅ Post successfully published.")
|
||||
|
Reference in New Issue
Block a user