Conditions | 12 |
Total Lines | 117 |
Code Lines | 76 |
Lines | 0 |
Ratio | 0 % |
Changes | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like tweet_generator.Bot.twitter() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | import io |
||
20 | @command( |
||
21 | name='twitter', |
||
22 | description='to create fake tweets', |
||
23 | guild=690604075775164437 |
||
24 | ) |
||
25 | async def twitter(self, ctx: MessageContext, content: Descripted[str, '...']): |
||
26 | await ctx.interaction.ack() |
||
27 | |||
28 | message = content |
||
29 | for text_match, user_id in re.findall(re.compile(r"(<@!(\d+)>)"), message): |
||
30 | print(str(await self.get_user(user_id))) |
||
31 | message = message.replace(text_match, '@' + str(await self.get_user(user_id))) |
||
32 | |||
33 | if len(message) > 280: |
||
34 | return 'A tweet can be at maximum 280 characters long' |
||
35 | |||
36 | # wrap the message to be multi-line |
||
37 | message = textwrap.wrap(message, 38) |
||
38 | |||
39 | # download the profile picture and convert it into Image object |
||
40 | request = urllib.request.Request( |
||
41 | f"https://cdn.discordapp.com/avatars/{ctx.author.user.id}/{ctx.author.user.avatar}.webp?size=128", |
||
42 | headers={ |
||
43 | 'User-Agent': 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.7) Gecko/2009021910 Firefox/3.0.7'} |
||
44 | ) |
||
45 | avatar = urllib.request.urlopen(request).read() |
||
46 | avatar = io.BytesIO(avatar) |
||
47 | avatar = Image.open(avatar).convert("RGBA").resize((128, 128)) |
||
48 | |||
49 | # modify profile picture to be circular |
||
50 | mask = Image.new('L', (128, 128), 0) |
||
51 | draw = ImageDraw.Draw(mask) |
||
52 | draw.ellipse((0, 0) + (128, 128), fill=255) |
||
53 | avatar = ImageOps.fit(avatar, mask.size, centering=(0.5, 0.5)) |
||
54 | avatar.putalpha(mask) |
||
55 | |||
56 | # create the tweet by pasting the profile picture into a white image |
||
57 | tweet = trans_paste( |
||
58 | avatar, |
||
59 | |||
60 | # background |
||
61 | Image.new('RGBA', (800, 250 + 50 * len(message)), (255, 255, 255)), |
||
62 | |||
63 | box=(15, 15) |
||
64 | ) |
||
65 | |||
66 | # add the fonts |
||
67 | font = ImageFont.truetype('Segoe UI.ttf', 40) |
||
68 | font_small = ImageFont.truetype('Segoe UI.ttf', 30) |
||
69 | font_bold = ImageFont.truetype('Segoe UI Bold.ttf', 40) |
||
70 | |||
71 | # write the name and username on the Image |
||
72 | draw = ImageDraw.Draw(tweet) |
||
73 | draw.text((180, 20), str(ctx.author.user), fill=(0, 0, 0), |
||
74 | font=font_bold) |
||
75 | draw.text((180, 70), '@' + ctx.author.user.username, fill=(120, 120, 120), |
||
76 | font=font) |
||
77 | |||
78 | # write the content of the tweet on the Image |
||
79 | message = '\n'.join(message).split(' ') |
||
80 | result = [] |
||
81 | |||
82 | # generate a dict to set were the text need to be in different color. |
||
83 | # for example, if a word starts with '@' it will be write in blue. |
||
84 | # example: |
||
85 | # [ |
||
86 | # {'color': (0, 0, 0), 'text': 'hello world '}, |
||
87 | # {'color': (0, 154, 234), 'text': '@drawbu'} |
||
88 | # ] |
||
89 | for word in message: |
||
90 | for i_o, o in enumerate(word.split('\n')): |
||
91 | |||
92 | o += '\n' if i_o != len(word.split('\n')) - 1 else ' ' |
||
93 | |||
94 | if not result: |
||
95 | result.append({'color': (0, 0, 0), 'text': o}) |
||
96 | continue |
||
97 | |||
98 | if not o.startswith('@'): |
||
99 | if result[-1:][0]['color'] == (0, 0, 0): |
||
100 | result[-1:][0]['text'] += o |
||
101 | continue |
||
102 | |||
103 | result.append({'color': (0, 0, 0), 'text': o}) |
||
104 | continue |
||
105 | |||
106 | result.append({'color': (0, 154, 234), 'text': o}) |
||
107 | |||
108 | # write the text |
||
109 | draw = ImageDraw.Draw(tweet) |
||
110 | x = 30 |
||
111 | y = 170 |
||
112 | for o in result: |
||
113 | y -= font.getsize(' ')[1] |
||
114 | for l_index, line in enumerate(o['text'].split('\n')): |
||
115 | if l_index != 0: |
||
116 | x = 30 |
||
117 | y += font.getsize(' ')[1] |
||
118 | draw.text((x, y), line, fill=o['color'], font=font) |
||
119 | x += font.getsize(line)[0] |
||
120 | |||
121 | # write the footer |
||
122 | draw.text( |
||
123 | (30, tweet.size[1] - 60), |
||
124 | datetime.now().strftime( |
||
125 | '%I:%M %p · %d %b. %Y · Twitter for Discord'), |
||
126 | fill=(120, 120, 120), |
||
127 | font=font_small) |
||
128 | |||
129 | return Message( |
||
130 | embeds=[ |
||
131 | Embed( |
||
132 | title='Twitter for Discord', |
||
133 | description='' |
||
134 | ).set_image(url="attachment://image0.png") |
||
135 | ], |
||
136 | attachments=[tweet] |
||
137 | ) |
||
156 |