Added length in RSS
This commit is contained in:
34
rss2bsky.py
34
rss2bsky.py
@@ -37,7 +37,7 @@ DEFAULT_COOLDOWN_STATE_PATH = "rss2bsky_cooldowns.json"
|
|||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class LimitsConfig:
|
class LimitsConfig:
|
||||||
dedupe_bsky_limit: int = 30
|
dedupe_bsky_limit: int = 30
|
||||||
bsky_text_max_length: int = 275
|
bsky_text_max_length: int = 300
|
||||||
|
|
||||||
external_thumb_max_bytes: int = 750 * 1024
|
external_thumb_max_bytes: int = 750 * 1024
|
||||||
external_thumb_target_bytes: int = 500 * 1024
|
external_thumb_target_bytes: int = 500 * 1024
|
||||||
@@ -402,7 +402,7 @@ def process_title(title: str) -> str:
|
|||||||
return title_text
|
return title_text
|
||||||
|
|
||||||
|
|
||||||
def build_post_text_variants(title_text: str, link: str):
|
def build_post_text_variants(title_text: str, link: str, max_length: int = 300):
|
||||||
title_text = clean_whitespace(title_text)
|
title_text = clean_whitespace(title_text)
|
||||||
link = canonicalize_url(link) or link or ""
|
link = canonicalize_url(link) or link or ""
|
||||||
|
|
||||||
@@ -415,16 +415,34 @@ def build_post_text_variants(title_text: str, link: str):
|
|||||||
seen.add(cleaned)
|
seen.add(cleaned)
|
||||||
variants.append(cleaned)
|
variants.append(cleaned)
|
||||||
|
|
||||||
|
# Variant 1: títol + link (si cap sencer)
|
||||||
if title_text and link:
|
if title_text and link:
|
||||||
add_variant(f"{title_text}\n\n{link}")
|
full = f"{title_text}\n\n{link}"
|
||||||
|
if len(full) <= max_length:
|
||||||
|
add_variant(full)
|
||||||
|
else:
|
||||||
|
# Trunca el títol per fer-hi lloc al link
|
||||||
|
# Reserva espai per "\n\n" + link
|
||||||
|
reserve = len(link) + 2
|
||||||
|
available = max_length - reserve
|
||||||
|
if available > 20:
|
||||||
|
truncated_title = title_text[:available - 3].rstrip() + "..."
|
||||||
|
add_variant(f"{truncated_title}\n\n{link}")
|
||||||
|
|
||||||
|
# Variant 2: només títol (truncat si cal)
|
||||||
if title_text:
|
if title_text:
|
||||||
|
if len(title_text) <= max_length:
|
||||||
add_variant(title_text)
|
add_variant(title_text)
|
||||||
|
else:
|
||||||
|
truncated = title_text[:max_length - 3].rstrip() + "..."
|
||||||
|
add_variant(truncated)
|
||||||
|
|
||||||
|
# Variant 3: només link (si no hi ha títol)
|
||||||
if link and not title_text:
|
if link and not title_text:
|
||||||
add_variant(link)
|
add_variant(link)
|
||||||
|
|
||||||
return variants
|
return variants
|
||||||
|
|
||||||
|
|
||||||
def is_x_or_twitter_domain(url: str) -> bool:
|
def is_x_or_twitter_domain(url: str) -> bool:
|
||||||
try:
|
try:
|
||||||
hostname = (urlparse(url).hostname or "").lower()
|
hostname = (urlparse(url).hostname or "").lower()
|
||||||
@@ -800,7 +818,7 @@ def try_send_post_with_variants(client: Client, text_variants: List[str], embed,
|
|||||||
reset_str = format_cooldown_until(get_global_post_cooldown_until(cooldown_path))
|
reset_str = format_cooldown_until(get_global_post_cooldown_until(cooldown_path))
|
||||||
raise RuntimeError(f"Posting skipped because global post cooldown is active until {reset_str}")
|
raise RuntimeError(f"Posting skipped because global post cooldown is active until {reset_str}")
|
||||||
|
|
||||||
logging.info(f"📝 Trying post text variant {idx}/{len(text_variants)} (length={len(variant)})")
|
logging.info(f"📝 Trying post text variant {idx}/{len(text_variants)} "f"(length={len(variant)} chars)")
|
||||||
rich_text = make_rich(variant)
|
rich_text = make_rich(variant)
|
||||||
result = client.send_post(text=rich_text, embed=embed, langs=[post_lang])
|
result = client.send_post(text=rich_text, embed=embed, langs=[post_lang])
|
||||||
return result, variant
|
return result, variant
|
||||||
@@ -1019,7 +1037,7 @@ def fetch_feed_content(feed_url: str, http_client: httpx.Client, cfg: AppConfig)
|
|||||||
return response.content.decode("utf-8", errors="ignore")
|
return response.content.decode("utf-8", errors="ignore")
|
||||||
|
|
||||||
|
|
||||||
def build_candidates_from_feed(feed) -> List[EntryCandidate]:
|
def build_candidates_from_feed(feed, max_length: int = 300) -> List[EntryCandidate]:
|
||||||
candidates: List[EntryCandidate] = []
|
candidates: List[EntryCandidate] = []
|
||||||
|
|
||||||
for item in getattr(feed, "entries", []):
|
for item in getattr(feed, "entries", []):
|
||||||
@@ -1043,7 +1061,7 @@ def build_candidates_from_feed(feed) -> List[EntryCandidate]:
|
|||||||
published_at=published_at.isoformat() if published_at else None,
|
published_at=published_at.isoformat() if published_at else None,
|
||||||
published_arrow=published_at,
|
published_arrow=published_at,
|
||||||
entry_fingerprint=entry_fingerprint,
|
entry_fingerprint=entry_fingerprint,
|
||||||
post_text_variants=build_post_text_variants(title_text, link),
|
post_text_variants=build_post_text_variants(title_text, link, max_length=max_length),
|
||||||
))
|
))
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -1168,7 +1186,7 @@ def run_once(
|
|||||||
with httpx.Client() as http_client:
|
with httpx.Client() as http_client:
|
||||||
feed_content = fetch_feed_content(rss_feed, http_client, cfg)
|
feed_content = fetch_feed_content(rss_feed, http_client, cfg)
|
||||||
feed = fastfeedparser.parse(feed_content)
|
feed = fastfeedparser.parse(feed_content)
|
||||||
candidates = build_candidates_from_feed(feed)
|
candidates = build_candidates_from_feed(feed, max_length=cfg.limits.bsky_text_max_length)
|
||||||
|
|
||||||
logging.info(f"📰 Prepared {len(candidates)} feed entry candidates for duplicate comparison.")
|
logging.info(f"📰 Prepared {len(candidates)} feed entry candidates for duplicate comparison.")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user