Add images to filter pages
This commit is contained in:
parent
9b569f64a8
commit
b610d7ef1a
3 changed files with 44 additions and 7 deletions
|
|
@ -5,6 +5,7 @@ import json
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from functools import lru_cache
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
|
|
@ -193,18 +194,40 @@ def replace_tags_in_text_message(entry: Entry, reader: Reader) -> str:
|
||||||
return custom_message.replace("\\n", "\n")
|
return custom_message.replace("\\n", "\n")
|
||||||
|
|
||||||
|
|
||||||
def get_first_image(summary: str | None, content: str | None) -> str:
|
@lru_cache(200)
|
||||||
|
def get_first_image(summary: str | None, content: str | None) -> str: # noqa: C901
|
||||||
"""Get image from summary or content.
|
"""Get image from summary or content.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
summary: The summary from the entry
|
summary: The summary from the entry (string, or tuple/list of objects)
|
||||||
content: The content from the entry
|
content: The content from the entry (string, or tuple/list of objects)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The first image
|
The first image
|
||||||
"""
|
"""
|
||||||
# TODO(TheLovinator): We should find a better way to get the image.
|
|
||||||
if content and (images := BeautifulSoup(content, features="lxml").find_all("img")):
|
def extract_string(data: str | list | tuple | None) -> str | None:
|
||||||
|
if not data:
|
||||||
|
return None
|
||||||
|
if isinstance(data, str):
|
||||||
|
return data
|
||||||
|
if isinstance(data, (list, tuple)):
|
||||||
|
extracted: list[str] = []
|
||||||
|
for item in data:
|
||||||
|
if hasattr(item, "value"):
|
||||||
|
extracted.append(item.value)
|
||||||
|
elif isinstance(item, dict) and "value" in item:
|
||||||
|
extracted.append(item.get("value", ""))
|
||||||
|
else:
|
||||||
|
extracted.append(str(item))
|
||||||
|
return "".join(extracted)
|
||||||
|
return str(data)
|
||||||
|
|
||||||
|
# Convert potentially complex objects into strings
|
||||||
|
content_str: str | None = extract_string(content)
|
||||||
|
summary_str: str | None = extract_string(summary)
|
||||||
|
|
||||||
|
if content_str and (images := BeautifulSoup(content_str, features="lxml").find_all("img")):
|
||||||
for image in images:
|
for image in images:
|
||||||
if not isinstance(image, Tag) or "src" not in image.attrs:
|
if not isinstance(image, Tag) or "src" not in image.attrs:
|
||||||
logger.error("Image is not a Tag or does not have a src attribute.")
|
logger.error("Image is not a Tag or does not have a src attribute.")
|
||||||
|
|
@ -215,8 +238,9 @@ def get_first_image(summary: str | None, content: str | None) -> str:
|
||||||
logger.warning("Invalid URL: %s", src)
|
logger.warning("Invalid URL: %s", src)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
return str(image.attrs["src"])
|
return src
|
||||||
if summary and (images := BeautifulSoup(summary, features="lxml").find_all("img")):
|
|
||||||
|
if summary_str and (images := BeautifulSoup(summary_str, features="lxml").find_all("img")):
|
||||||
for image in images:
|
for image in images:
|
||||||
if not isinstance(image, Tag) or "src" not in image.attrs:
|
if not isinstance(image, Tag) or "src" not in image.attrs:
|
||||||
logger.error("Image is not a Tag or does not have a src attribute.")
|
logger.error("Image is not a Tag or does not have a src attribute.")
|
||||||
|
|
@ -227,6 +251,7 @@ def get_first_image(summary: str | None, content: str | None) -> str:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
return str(image.attrs["src"])
|
return str(image.attrs["src"])
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -522,6 +522,7 @@ async def get_whitelist_preview(
|
||||||
"""
|
"""
|
||||||
clean_feed_url: str = urllib.parse.unquote(feed_url.strip())
|
clean_feed_url: str = urllib.parse.unquote(feed_url.strip())
|
||||||
feed: Feed = reader.get_feed(clean_feed_url)
|
feed: Feed = reader.get_feed(clean_feed_url)
|
||||||
|
|
||||||
form_values: dict[str, str] = {
|
form_values: dict[str, str] = {
|
||||||
"whitelist_title": whitelist_title,
|
"whitelist_title": whitelist_title,
|
||||||
"whitelist_summary": whitelist_summary,
|
"whitelist_summary": whitelist_summary,
|
||||||
|
|
@ -760,6 +761,7 @@ def build_filter_preview_context(
|
||||||
"published_label": published_label,
|
"published_label": published_label,
|
||||||
"status_label": "Sent" if decision.should_send else "Skipped",
|
"status_label": "Sent" if decision.should_send else "Skipped",
|
||||||
"status_class": "success" if decision.should_send else "danger",
|
"status_class": "success" if decision.should_send else "danger",
|
||||||
|
"first_image": get_first_image(summary=entry.summary, content=entry.content),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,16 @@
|
||||||
</section>
|
</section>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="filter-preview__field-table mt-2"
|
||||||
|
style="max-width: 600px;
|
||||||
|
max-height: 300px;
|
||||||
|
overflow: hidden">
|
||||||
|
<img class="img-fluid w-100"
|
||||||
|
style="object-fit: cover;
|
||||||
|
height: 100%"
|
||||||
|
alt="Image for {{ row.entry.title }}"
|
||||||
|
src="{{ row.first_image }}">
|
||||||
|
</div>
|
||||||
</article>
|
</article>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue