Passed
Pull Request — main (#241)
by
unknown
01:32
created

tweet_generator   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 150
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 14
eloc 94
dl 0
loc 150
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 111 12

1 Function

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