| Conditions | 12 |
| Total Lines | 118 |
| Code Lines | 72 |
| 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 re |
||
| 17 | @command( |
||
| 18 | name="twitter", |
||
| 19 | description="to create fake tweets", |
||
| 20 | ) |
||
| 21 | async def twitter( |
||
| 22 | self, ctx: MessageContext, content: Descripted[str, "..."] |
||
| 23 | ): |
||
| 24 | await ctx.interaction.ack() |
||
| 25 | |||
| 26 | message = content |
||
| 27 | for text_match, user_id in re.findall( |
||
| 28 | re.compile(r"(<@!(\d+)>)"), message |
||
| 29 | ): |
||
| 30 | message = message.replace( |
||
| 31 | text_match, "@%s" % await self.get_user(user_id) |
||
| 32 | ) |
||
| 33 | |||
| 34 | if len(message) > 280: |
||
| 35 | return "A tweet can be at maximum 280 characters long" |
||
| 36 | |||
| 37 | # wrap the message to be multi-line |
||
| 38 | message = textwrap.wrap(message, 38) |
||
| 39 | |||
| 40 | # download the profile picture and convert it into Image object |
||
| 41 | avatar = (await ctx.author.user.get_avatar()).resize((128, 128)) |
||
| 42 | |||
| 43 | # modify profile picture to be circular |
||
| 44 | mask = Image.new("L", (128, 128), 0) |
||
| 45 | draw = ImageDraw.Draw(mask) |
||
| 46 | draw.ellipse((0, 0) + (128, 128), fill=255) |
||
| 47 | avatar = ImageOps.fit(avatar, mask.size, centering=(0.5, 0.5)) |
||
| 48 | avatar.putalpha(mask) |
||
| 49 | |||
| 50 | # create the tweet by pasting the profile picture into a white image |
||
| 51 | tweet = trans_paste( |
||
| 52 | avatar, |
||
| 53 | # background |
||
| 54 | Image.new("RGBA", (800, 250 + 50 * len(message)), (255, 255, 255)), |
||
| 55 | box=(15, 15), |
||
| 56 | ) |
||
| 57 | |||
| 58 | # add the fonts |
||
| 59 | font = ImageFont.truetype("Segoe_UI.ttf", 40) |
||
| 60 | font_small = ImageFont.truetype("Segoe_UI.ttf", 30) |
||
| 61 | font_bold = ImageFont.truetype("Segoe_UI_Bold.ttf", 40) |
||
| 62 | |||
| 63 | # write the name and username on the Image |
||
| 64 | draw = ImageDraw.Draw(tweet) |
||
| 65 | draw.text( |
||
| 66 | (180, 20), str(ctx.author.user), fill=(0, 0, 0), font=font_bold |
||
| 67 | ) |
||
| 68 | draw.text( |
||
| 69 | (180, 70), |
||
| 70 | "@" + ctx.author.user.username, |
||
| 71 | fill=(120, 120, 120), |
||
| 72 | font=font, |
||
| 73 | ) |
||
| 74 | |||
| 75 | # write the content of the tweet on the Image |
||
| 76 | message = "\n".join(message).split() |
||
| 77 | result = [] |
||
| 78 | |||
| 79 | # generate a dict to set were the text need to be in different color. |
||
| 80 | # for example, if a word starts with '@' it will be write in blue. |
||
| 81 | # example: |
||
| 82 | # [ |
||
| 83 | # {'color': (0, 0, 0), 'text': 'hello world '}, |
||
| 84 | # {'color': (0, 154, 234), 'text': '@drawbu'} |
||
| 85 | # ] |
||
| 86 | for word in message: |
||
| 87 | for index, text in enumerate(word.split("\n")): |
||
| 88 | |||
| 89 | text += "\n" if index != len(word.split("\n")) - 1 else " " |
||
| 90 | |||
| 91 | if not result: |
||
| 92 | result.append({"color": (0, 0, 0), "text": text}) |
||
| 93 | continue |
||
| 94 | |||
| 95 | if not text.startswith("@"): |
||
| 96 | if result[-1:][0]["color"] == (0, 0, 0): |
||
| 97 | result[-1:][0]["text"] += text |
||
| 98 | continue |
||
| 99 | |||
| 100 | result.append({"color": (0, 0, 0), "text": text}) |
||
| 101 | continue |
||
| 102 | |||
| 103 | result.append({"color": (0, 154, 234), "text": text}) |
||
| 104 | |||
| 105 | # write the text |
||
| 106 | draw = ImageDraw.Draw(tweet) |
||
| 107 | x = 30 |
||
| 108 | y = 170 |
||
| 109 | for text in result: |
||
| 110 | y -= font.getsize(" ")[1] |
||
| 111 | for l_index, line in enumerate(text["text"].split("\n")): |
||
| 112 | if l_index != 0: |
||
| 113 | x = 30 |
||
| 114 | y += font.getsize(" ")[1] |
||
| 115 | draw.text((x, y), line, fill=text["color"], font=font) |
||
| 116 | x += font.getsize(line)[0] |
||
| 117 | |||
| 118 | # write the footer |
||
| 119 | draw.text( |
||
| 120 | (30, tweet.size[1] - 60), |
||
| 121 | datetime.now().strftime( |
||
| 122 | "%I:%M %p · %d %b. %Y · Twitter for Discord" |
||
| 123 | ), |
||
| 124 | fill=(120, 120, 120), |
||
| 125 | font=font_small, |
||
| 126 | ) |
||
| 127 | |||
| 128 | return Message( |
||
| 129 | embeds=[ |
||
| 130 | Embed(title="Twitter for Discord", description="").set_image( |
||
| 131 | url="attachment://image0.png" |
||
| 132 | ) |
||
| 133 | ], |
||
| 134 | attachments=[tweet], |
||
| 135 | ) |
||
| 154 |