]>
git.scottworley.com Git - paperdoorknob/blob - glowfic.py
1 # paperdoorknob: Print glowfic
3 # This program is free software: you can redistribute it and/or modify it
4 # under the terms of the GNU General Public License as published by the
5 # Free Software Foundation, version 3.
8 from dataclasses
import dataclass
11 from typing
import Iterable
13 from bs4
import BeautifulSoup
14 from bs4
.element
import Tag
16 from images
import ImageStore
19 @dataclass(frozen
=True)
23 screen_name
: str |
None
27 # We avoid the name "post" because the Glowfic community uses the term
29 # * The Glowfic software sometimes uses "post" to refer to a whole thread
30 # (in the URL), sometimes uses "post" to refer to chunks (in the CSS),
31 # but mostly uses "post" to refer to just the first chunk in a thread
32 # (in the HTML and UI). The non-first chunks are "replies".
33 # * Readers and this software don't need to distinguish first-chunks and
35 # * Humans in the community tend to use "posts" to mean chunks.
38 def chunkDOMs(html
: BeautifulSoup
) -> Iterable
[Tag
]:
42 text
= body
.find_next("div", class_
="post-post")
43 assert isinstance(text
, Tag
)
46 def the_replies() -> Iterable
[Tag
]:
47 rs
= html
.find_all("div", class_
="post-reply")
48 assert all(isinstance(r
, Tag
) for r
in rs
)
51 return itertools
.chain([text()], the_replies())
54 def makeChunk(chunk_dom
: Tag
, image_store
: ImageStore
) -> Chunk
:
56 def getIcon() -> str |
None:
57 icon_div
= chunk_dom
.find_next('div', class_
='post-icon')
60 icon_img
= icon_div
.find_next('img')
63 assert isinstance(icon_img
, Tag
)
64 return image_store
.get_image(icon_img
.attrs
['src'])
66 def getTextByClass(css_class
: str) -> str |
None:
67 div
= chunk_dom
.find_next('div', class_
=css_class
)
70 return div
.text
.strip()
72 content
= chunk_dom
.find_next('div', class_
='post-content')
73 assert isinstance(content
, Tag
)
75 return Chunk(getIcon(),
76 getTextByClass('post-character'),
77 getTextByClass('post-screenname'),
78 getTextByClass('post-author'),