-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfood_post.py
135 lines (119 loc) · 4.78 KB
/
food_post.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
from datetime import datetime
from image_util import compute_image_hash
from typing import Dict, Optional
GALLERY_URL = "https://www.reddit.com/gallery/"
DATETIME_FMT = "%d/%m/%y %H:%M"
class FoodPost:
# Attributes
# id - the submission ID given by Reddit
# title - the Post title
# post_url - the permalink for this post
# image_url - the url for the associated image of a submission
def __init__(self, **kwargs):
self.id = kwargs.get("id")
self.title = kwargs.get("title")
self.post_url = kwargs.get("permalink")
self.image_url = kwargs.get("image_url")
self.img_hash = kwargs.get("img_hash") # for testing
self.color = 0xDB5172
ts = kwargs.get("created_utc")
if ts is not None and ts > 0:
self.date_posted = datetime.fromtimestamp(ts)
else:
self.date_posted = None
def __str__(self):
return f"{self.title} : {self.post_url}"
def __repr__(self):
return self.__str__()
# Transforms this FoodPost object into the discord Embed dictionary that
# should be posted.
def to_embed(self) -> Dict:
data = {
"title": FoodPost.truncate(self.title),
"description": self.post_url,
"color": self.color,
}
if self.image_url is not None and self.image_url != "":
data["image"] = {"url": self.image_url}
return data
def image_hash(self) -> Optional[int]:
if self.img_hash is None:
self.img_hash = compute_image_hash(self.image_url)
return self.img_hash
def to_json(self) -> Dict:
"""
Transform the submission and it's hash into a Python
dictionary, so that it can be converted into a JSON string
that gets persisted in the Redis cache as part of an array.
Example:
{
"id": "foo-bar-baz",
"hash": "1234567890",
"title" "Something here",
"date": "2022-01-01",
}
@param img_hash the hash of the byte array of the Image from PIL
@return dictionary to be persisted into the Redis cache.
"""
return {
"id": self.id,
"hash": str(self.image_hash()),
"title": self.title,
"date": self.date_posted.strftime(DATETIME_FMT),
}
# Given a Reddit submission title, truncate the title if it's too long
# https://github.com/SaxyPandaBear/discord-food-bot/issues/28
# If the title is not too long, return the input unchanged
@staticmethod
def truncate(title: str) -> str:
if title is None:
return None
# truncate with an ellipsis, so we need some leeway
if len(title) > 256:
return title[:253] + "..." # take first 253 characters
return title
# Take a Reddit submission object, and transform that into a FoodPost
@staticmethod
def from_submission(submission):
sub_id = submission.id
url = FoodPost.derive_image_url(submission)
# permalink does not give the full URL, so build it instead.
permalink = f"https://www.reddit.com{submission.permalink}"
title = submission.title
created_utc = submission.created_utc
return FoodPost(
id=sub_id,
title=title,
image_url=url,
permalink=permalink,
created_utc=created_utc,
)
@staticmethod
def derive_image_url(submission) -> Optional[str]:
"""
A submission can point to a gallery instead of a direct link to
an image. This gallery URL does not render properly on Discord in the
embed. Have to pick one of the images ourselves, and then use that
to display in this scenario.
@param submission The submission object from PRAW
"""
if submission is None or submission.url is None:
return None
url = submission.url
if url.startswith(GALLERY_URL):
# https://github.com/SaxyPandaBear/my-webhooks/issues/4
# If the submission points to a Reddit gallery, need to pick one
# of the images in the gallery to render in the Discord embed.
# The set of images are defined in the "media_metadata" attribute
# of the submission.
images: Dict = submission.media_metadata
if images is None or len(images) < 1:
return None
# Unsure if ordering is guaranteed, so in order to be
# deterministic, ensure ordering on our end by sorting.
ids = sorted(images) # this sorts by key, and only returns keys.
url = f"https://i.redd.it/{ids[0]}.jpg"
query_param_idx = url.find("?")
if query_param_idx >= 0:
url = url[:query_param_idx]
return url