Passed
Pull Request — main (#241)
by Yohann
01:39
created

tweet_generator   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 145
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 14
eloc 90
dl 0
loc 145
rs 10
c 0
b 0
f 0

2 Methods

Rating   Name   Duplication   Size   Complexity  
A Bot.on_ready() 0 5 1
D Bot.twitter() 0 108 12

1 Function

Rating   Name   Duplication   Size   Complexity  
A trans_paste() 0 8 1
1
import re
2
import textwrap
3
from datetime import datetime
4
from PIL import Image, ImageFont, ImageDraw, ImageOps
5
from pincer import command, Client, Descripted
6
from pincer.objects import Message, Embed, MessageContext
7
8
9
class Bot(Client):
10
11
    @Client.event
12
    async def on_ready(self):
13
        print(
14
            f"Started client on {self.bot}\n"
15
            "Registered commands: " + ", ".join(self.chat_commands)
16
        )
17
18
    @command(
19
        name='twitter',
20
        description='to create fake tweets',
21
        guild=690604075775164437
22
    )
23
    async def twitter(self, ctx: MessageContext, content: Descripted[str, '...']):
24
        await ctx.interaction.ack()
25
26
        message = content
27
        for text_match, user_id in re.findall(re.compile(r"(<@!(\d+)>)"), message):
28
            message = message.replace(text_match, '@' + str(await self.get_user(user_id)))
29
30
        if len(message) > 280:
31
            return 'A tweet can be at maximum 280 characters long'
32
33
        # wrap the message to be multi-line
34
        message = textwrap.wrap(message, 38)
35
36
        avatar = (await ctx.author.user.get_avatar()).resize((128, 128))
37
38
        # modify profile picture to be circular
39
        mask = Image.new('L', (128, 128), 0)
40
        draw = ImageDraw.Draw(mask)
41
        draw.ellipse((0, 0) + (128, 128), fill=255)
42
        avatar = ImageOps.fit(avatar, mask.size, centering=(0.5, 0.5))
43
        avatar.putalpha(mask)
44
45
        # create the tweet by pasting the profile picture into a white image
46
        tweet = trans_paste(
47
            avatar,
48
49
            # background
50
            Image.new('RGBA', (800, 250 + 50 * len(message)), (255, 255, 255)),
51
52
            box=(15, 15)
53
        )
54
55
        # add the fonts
56
        font = ImageFont.truetype('Segoe UI.ttf', 40)
57
        font_small = ImageFont.truetype('Segoe UI.ttf', 30)
58
        font_bold = ImageFont.truetype('Segoe UI Bold.ttf', 40)
59
60
        # write the name and username on the Image
61
        draw = ImageDraw.Draw(tweet)
62
        draw.text((180, 20), str(ctx.author.user), fill=(0, 0, 0),
63
                  font=font_bold)
64
        draw.text((180, 70), '@' + ctx.author.user.username, fill=(120, 120, 120),
65
                  font=font)
66
67
        # write the content of the tweet on the Image
68
        message = '\n'.join(message).split(' ')
69
        result = []
70
71
        # generate a dict to set were the text need to be in different color.
72
        # for example, if a word starts with '@' it will be write in blue.
73
        # example:
74
        #   [
75
        #       {'color': (0, 0, 0), 'text': 'hello world '},
76
        #       {'color': (0, 154, 234), 'text': '@drawbu'}
77
        #   ]
78
        for word in message:
79
            for i_o, o in enumerate(word.split('\n')):
80
81
                o += '\n' if i_o != len(word.split('\n')) - 1 else ' '
82
83
                if not result:
84
                    result.append({'color': (0, 0, 0), 'text': o})
85
                    continue
86
87
                if not o.startswith('@'):
88
                    if result[-1:][0]['color'] == (0, 0, 0):
89
                        result[-1:][0]['text'] += o
90
                        continue
91
92
                    result.append({'color': (0, 0, 0), 'text': o})
93
                    continue
94
95
                result.append({'color': (0, 154, 234), 'text': o})
96
97
        # write the text
98
        draw = ImageDraw.Draw(tweet)
99
        x = 30
100
        y = 170
101
        for o in result:
102
            y -= font.getsize(' ')[1]
103
            for l_index, line in enumerate(o['text'].split('\n')):
104
                if l_index != 0:
105
                    x = 30
106
                y += font.getsize(' ')[1]
107
                draw.text((x, y), line, fill=o['color'], font=font)
108
                x += font.getsize(line)[0]
109
110
        # write the footer
111
        draw.text(
112
            (30, tweet.size[1] - 60),
113
            datetime.now().strftime(
114
                '%I:%M %p · %d %b. %Y · Twitter for Discord'),
115
            fill=(120, 120, 120),
116
            font=font_small)
117
118
        return Message(
119
            embeds=[
120
                Embed(
121
                    title='Twitter for Discord',
122
                    description=''
123
                ).set_image(url="attachment://image0.png")
124
            ],
125
            attachments=[tweet]
126
        )
127
128
129
# https://stackoverflow.com/a/53663233/15485584
130
def trans_paste(fg_img, bg_img, alpha=1.0, box=(0, 0)):
131
    """
132
    paste an image into one another
133
    """
134
    fg_img_trans = Image.new("RGBA", fg_img.size)
135
    fg_img_trans = Image.blend(fg_img_trans, fg_img, alpha)
136
    bg_img.paste(fg_img_trans, box, fg_img_trans)
137
    return bg_img
138
139
140
if __name__ == "__main__":
141
    # Of course we have to run our client, you can replace the
142
    # XXXYOURBOTTOKENHEREXXX with your token, or dynamically get it
143
    # through a dotenv/env.
144
    Bot("XXXYOURBOTTOKENHEREXXX").run()
145