From e4b30fd9bd25f8b5d87b0d804a058654575d00f6 Mon Sep 17 00:00:00 2001 From: syeopite <70992037+syeopite@users.noreply.github.com> Date: Thu, 2 Jan 2025 23:07:59 +0000 Subject: [PATCH] Add support for Tumblr signposts (#171) These are timeline objects typically used to warn of restricted searches Center signpost elements Add margin to signpost elements Allow signposts to be cached Fallback to "" when description is unavailable Minor CSS organization improvements --- assets/css/base.css | 8 +++- assets/css/timeline.css | 45 +++++++++++++++++++ src/priviblur_extractor/models/__init__.py | 2 +- src/priviblur_extractor/models/misc.py | 15 +++++++ src/priviblur_extractor/models/timelines.py | 13 ++++-- .../parse/collection_parsers.py | 7 ++- src/priviblur_extractor/parse/items.py | 16 +++++++ src/templates/components/signpost.jinja | 7 +++ .../macros/insert_content_list.jinja | 2 + src/templates/timeline.jinja | 3 ++ 10 files changed, 110 insertions(+), 8 deletions(-) create mode 100644 assets/css/timeline.css create mode 100644 src/priviblur_extractor/models/misc.py create mode 100644 src/templates/components/signpost.jinja diff --git a/assets/css/base.css b/assets/css/base.css index 09370fae..169cda40 100644 --- a/assets/css/base.css +++ b/assets/css/base.css @@ -142,6 +142,9 @@ body { --color-setting-option-desc: var(--light, var(--color-gray-500)) var(--dark, var(--color-dt-gray-250)); --color-settings-theme-select-outline: var(--light, var(--color-primary-400)) var(--dark, var(--color-primary-400)); --color-settings-dropdown-option-bg: var(--light, var(--color-gray-200)) var(--dark, var(--color-dt-gray-400)); + + --tumblr-signpost-bg: var(--light, var(--color-gray-125)) var(--dark, var(--color-dt-gray-700)); + --tumblr-signpost-border: var(--light, var(--color-gray-300)) var(--dark, var(--color-dt-gray-500)); } html, body, .container { @@ -323,8 +326,9 @@ a.logo { .timeline, .blog-posts { display: flex; + flex-direction: column; + align-items: center; gap: 2em; - flex-wrap: wrap; max-width: 590px; } @@ -498,4 +502,4 @@ li.no-js .control-bar-dropdown-menu { .page-footer a { text-decoration: underline; -} \ No newline at end of file +} diff --git a/assets/css/timeline.css b/assets/css/timeline.css new file mode 100644 index 00000000..c2dd0cd6 --- /dev/null +++ b/assets/css/timeline.css @@ -0,0 +1,45 @@ +/* This file contains the styling for various Tumblr timeline objects */ + +.tumblr-signpost { + display: flex; + flex-direction: row; + align-items: center; + gap: 20px; + + width: 350px; + box-sizing: border-box; + overflow: hidden; + + margin: 0 20px; + padding: 20px 25px; + + background: var(--tumblr-signpost-bg); + color: var(--color-text); + border: 2px solid var(--tumblr-signpost-border); + border-radius: 10px; + + box-shadow: rgba(0,0,0,0.2) 0px 1px 3px; + } + + .tumblr-signpost svg { + min-width: max-content; + } + + .tumblr-signpost p { + line-height: 2; + font-size: 12px; + } + + .tumblr-signpost h3 { + font-weight: bold; + margin: 0; + margin-bottom: 10px; + font-size: 14px; + } + + + @media (max-width: 350px) { + .tumblr-signpost { + width: auto; + } + } diff --git a/src/priviblur_extractor/models/__init__.py b/src/priviblur_extractor/models/__init__.py index 34b5b058..a78f68b5 100644 --- a/src/priviblur_extractor/models/__init__.py +++ b/src/priviblur_extractor/models/__init__.py @@ -1,3 +1,3 @@ -from . import base, blog, post, timelines +from . import base, blog, post, timelines, misc from .base import VERSION \ No newline at end of file diff --git a/src/priviblur_extractor/models/misc.py b/src/priviblur_extractor/models/misc.py new file mode 100644 index 00000000..655a3b9f --- /dev/null +++ b/src/priviblur_extractor/models/misc.py @@ -0,0 +1,15 @@ +from typing import NamedTuple, Optional + +class Signpost(NamedTuple): + title: str + description: Optional[str] = None + + def to_json_serialisable(self): + return { + "title": self.title, + "description": self.description + } + + @classmethod + def from_json(cls, json): + return cls(**json) diff --git a/src/priviblur_extractor/models/timelines.py b/src/priviblur_extractor/models/timelines.py index 1132debf..f7292718 100644 --- a/src/priviblur_extractor/models/timelines.py +++ b/src/priviblur_extractor/models/timelines.py @@ -3,6 +3,7 @@ from . import base from .post import Post, ReplyNote, ReblogNote, LikeNote +from .misc import Signpost from. blog import Blog @@ -102,10 +103,12 @@ class Timeline(NamedTuple): def to_json_serialisable(self): elements = [] for element in self.elements: - if isinstance(element, Blog): + if isinstance(element, Post): + elements.append({"post": element.to_json_serialisable()}) + elif isinstance(element, Blog): elements.append({"blog": element.to_json_serialisable()}) else: - elements.append({"post": element.to_json_serialisable()}) + elements.append({"signpost": element.to_json_serialisable()}) next_ = self.next if next_: @@ -121,10 +124,12 @@ def to_json_serialisable(self): def from_json(cls, json): elements = [] for element in json["elements"]: - if blog := element.get("blog"): + if post := element.get("post"): + elements.append(Post.from_json(post)) + elif blog := element.get("blog"): elements.append(Blog.from_json(blog)) else: - elements.append(Post.from_json(element["post"])) + elements.append(Signpost.from_json(element["signpost"])) json["elements"] = elements diff --git a/src/priviblur_extractor/parse/collection_parsers.py b/src/priviblur_extractor/parse/collection_parsers.py index 8386cd7f..9b89bd8e 100644 --- a/src/priviblur_extractor/parse/collection_parsers.py +++ b/src/priviblur_extractor/parse/collection_parsers.py @@ -53,7 +53,12 @@ def parse(self): elements = [] total_raw_elements = len(self.target["elements"]) for element_index, element in enumerate(self.target["elements"]): - if result := items.parse_item(element, element_index, total_raw_elements): + if result := items.parse_item( + element, + element_index, + total_raw_elements, + use_parsers=(items.PostParser, items.SignpostParser) + ): elements.append(result) return models.timelines.Timeline( diff --git a/src/priviblur_extractor/parse/items.py b/src/priviblur_extractor/parse/items.py index 4c027893..16de0477 100644 --- a/src/priviblur_extractor/parse/items.py +++ b/src/priviblur_extractor/parse/items.py @@ -349,6 +349,22 @@ def parse(self): ) +class SignpostParser: + def __init__(self, target) -> None: + self.target = target + + @classmethod + def process(cls, initial_data): + if initial_data.get("objectType") == "signpost_cta": + return cls(initial_data).parse() + + def parse(self): + return models.misc.Signpost( + title=self.target["display"]["title"], + description=helpers.dig_dict(self.target, ("resources", "description")), + ) + + def parse_item(element, element_index=0, total_elements=1, use_parsers=None): """Parses an item from Tumblr API's JSON response into a more usable structure""" item_number = f"({element_index + 1}/{total_elements})" diff --git a/src/templates/components/signpost.jinja b/src/templates/components/signpost.jinja new file mode 100644 index 00000000..378ed34f --- /dev/null +++ b/src/templates/components/signpost.jinja @@ -0,0 +1,7 @@ +
+ +
+

{{element.title}}

+

{{element.description or ""}}

+
+
\ No newline at end of file diff --git a/src/templates/macros/insert_content_list.jinja b/src/templates/macros/insert_content_list.jinja index 63b8830c..8b2e87fa 100644 --- a/src/templates/macros/insert_content_list.jinja +++ b/src/templates/macros/insert_content_list.jinja @@ -5,6 +5,8 @@ {%- if not element.is_advertisement -%} {%- include 'post/post.jinja' -%} {%- endif -%} + {% else %} + {%- include 'components/signpost.jinja' -%} {% endif %} {%- endfor -%} diff --git a/src/templates/timeline.jinja b/src/templates/timeline.jinja index 7cb57b32..a926a833 100644 --- a/src/templates/timeline.jinja +++ b/src/templates/timeline.jinja @@ -1,5 +1,8 @@ {% extends "base.jinja" %} {% from 'macros/insert_content_list.jinja' import insert_content_list with context %} + + +{% block head %}{% endblock %} {% block title %}{{title}}{% endblock%} {% block center %}