""" Post Utilities """ import json from typing import Dict __all__ = ["Post"] from substack.exceptions import SectionNotExistsException class Post: """ Post utility class """ def __init__( self, title: str, subtitle: str, user_id, audience: str = None, write_comment_permissions: str = None, ): """ Args: title: subtitle: user_id: audience: possible values: everyone, only_paid, founding, only_free write_comment_permissions: none, only_paid, everyone (this field is a mess) """ self.draft_title = title self.draft_subtitle = subtitle self.draft_body = {"type": "doc", "content": []} self.draft_bylines = [{"id": int(user_id), "is_guest": False}] self.audience = audience if audience is not None else "everyone" self.draft_section_id = None self.section_chosen = True # TODO better understand the possible values and combinations with audience if write_comment_permissions is not None: self.write_comment_permissions = write_comment_permissions else: self.write_comment_permissions = self.audience def set_section(self, name: str, sections: list): """ Args: name: sections: Returns: """ section = [s for s in sections if s.get("name") == name] if len(section) != 1: raise SectionNotExistsException(name) section = section[0] self.draft_section_id = section.get("id") def add(self, item: Dict): """ Add item to draft body. Args: item: Returns: """ self.draft_body["content"] = self.draft_body.get("content", []) + [ {"type": item.get("type")} ] content = item.get("content") if item.get("type") == "captionedImage": self.captioned_image(**item) elif item.get("type") == "embeddedPublication": self.draft_body["content"][-1]["attrs"] = item.get("url") elif item.get("type") == "youtube2": self.youtube(item.get("src")) elif item.get("type") == "subscribeWidget": self.subscribe_with_caption(item.get("message")) else: if content is not None: self.add_complex_text(content) if item.get("type") == "heading": self.attrs(item.get("level", 1)) marks = item.get("marks") if marks is not None: self.marks(marks) return self def paragraph(self, content=None): """ Args: content: Returns: """ item = {"type": "paragraph"} if content is not None: item["content"] = content return self.add(item) def heading(self, content=None, level: int = 1): """ Args: content: level: Returns: """ item = {"type": "heading"} if content is not None: item["content"] = content item["level"] = level return self.add(item) def horizontal_rule(self): """ Returns: """ return self.add({"type": "horizontal_rule"}) def attrs(self, level): """ Args: level: Returns: """ content_attrs = self.draft_body["content"][-1].get("attrs", {}) content_attrs.update({"level": level}) self.draft_body["content"][-1]["attrs"] = content_attrs return self def captioned_image( self, src: str, fullscreen: bool = False, imageSize: str = "normal", height: int = 819, width: int = 1456, resizeWidth: int = 728, bytes: str = None, alt: str = None, title: str = None, type: str = None, href: str = None, belowTheFold: bool = False, internalRedirect: str = None, ): """ Add image to body. Args: bytes: alt: title: type: href: belowTheFold: internalRedirect: src: fullscreen: imageSize: height: width: resizeWidth: """ content = self.draft_body["content"][-1].get("content", []) content += [ { "type": "image2", "attrs": { "src": src, "fullscreen": fullscreen, "imageSize": imageSize, "height": height, "width": width, "resizeWidth": resizeWidth, "bytes": bytes, "alt": alt, "title": title, "type": type, "href": href, "belowTheFold": belowTheFold, "internalRedirect": internalRedirect, }, } ] self.draft_body["content"][-1]["content"] = content return self def text(self, value: str): """ Add text to the last paragraph. Args: value: Text to add to paragraph. Returns: """ content = self.draft_body["content"][-1].get("content", []) content += [{"type": "text", "text": value}] self.draft_body["content"][-1]["content"] = content return self def add_complex_text(self, text): """ Args: text: """ if isinstance(text, str): self.text(text) else: for chunk in text: if chunk: self.text(chunk.get("content")).marks(chunk.get("marks", [])) def marks(self, marks): """ Args: marks: Returns: """ content = self.draft_body["content"][-1].get("content", [])[-1] content_marks = content.get("marks", []) for mark in marks: new_mark = {"type": mark.get("type")} if mark.get("type") == "link": href = mark.get("href") new_mark.update({"attrs": {"href": href}}) content_marks.append(new_mark) content["marks"] = content_marks return self def remove_last_paragraph(self): """Remove last paragraph""" del self.draft_body.get("content")[-1] def get_draft(self): """ Returns: """ out = vars(self) out["draft_body"] = json.dumps(out["draft_body"]) return out def subscribe_with_caption(self, message: str = None): """ Add subscribe widget with caption Args: message: Returns: """ if message is None: message = """Thanks for reading this newsletter! Subscribe for free to receive new posts and support my work.""" subscribe = self.draft_body["content"][-1] subscribe["attrs"] = { "url": "%%checkout_url%%", "text": "Subscribe", "language": "en", } subscribe["content"] = [ { "type": "ctaCaption", "content": [ { "type": "text", "text": message, } ], } ] return self def youtube(self, value: str): """ Add youtube video to post. Args: value: youtube url Returns: """ content_attrs = self.draft_body["content"][-1].get("attrs", {}) content_attrs.update({"videoId": value}) self.draft_body["content"][-1]["attrs"] = content_attrs return self