Issues (29)

fizzbotz/responses.py (2 issues)

1
import aiohttp
2
import asyncio
3
import html
4
import random
5
import re
6
import string
7
8
import bs4
9
10
import fizzbotz.util as util
11
from fizzbotz.exceptions import StringLengthError, EmptyStringError
12
13
14
class TwitchChat:
15
    def __init__(self):
16
        self._bestoftwitchchat_url = \
17
            'http://www.thebestoftwitch.com/feeds/posts/summary?' \
18
            'start-index={}&max-results=1'
19
        self._bestoftwitchchat_regex = re.compile(
20
            '<summary type="text">(.*)</summary>', re.DOTALL)
21
22
        self._twitchquotes_url = 'http://www.twitchquotes.com/random'
23
        self._twitchquotes_regex = re.compile(
24
            '<img class="emoticon" data-emote="(.*?)" src=".*?"/>', re.DOTALL)
25
26
    @asyncio.coroutine
27
    def get_bestoftwitchchat_pasta(self, from_html=None):
28
        # TODO: programmatically discover max index
29
        index = random.randint(1, 1104)
30
        url = self._bestoftwitchchat_url.format(index)
31
        if from_html is None:
32
            text = yield from util.get_markup(url)
33
        else:
34
            text = from_html
35
36
        raw_pasta = self._bestoftwitchchat_regex.search(text)
37
        pasta = raw_pasta.group(1)
38
        return html.unescape(pasta.strip())
39
40
    @asyncio.coroutine
41
    def get_twitchquotes_pasta(self, from_html=None):
42
        if from_html is None:
43
            text = yield from util.get_markup(self._twitchquotes_url)
44
        else:
45
            text = from_html
46
47
        raw_quote = self._twitchquotes_regex.sub(r'\1', text)
48
        parsed_quote = bs4.BeautifulSoup(raw_quote, 'html.parser')
49
        pasta = parsed_quote.find('div', class_='show_quote_text_area')
50
        if pasta is None:
51
            pasta = parsed_quote.find('span', id="quote_content_")
52
            return pasta.string.replace(' ', '\n').\
53
                strip(string.whitespace + "\"")
54
55
        return pasta.string.strip(string.whitespace + "\"")
56
57
    @asyncio.coroutine
58
    def get(self):
59
        pasta_funcs = (self.get_bestoftwitchchat_pasta,
60
                       self.get_twitchquotes_pasta)
61
        result = yield from random.choice(pasta_funcs)()
62
        return result
63
64
65
class Joke:
66
    def __init__(self):
67
        self._url = 'http://www.randomjoke.com/topic/oneliners.php'
68
        self._joke_regex = re.compile('(.*?)\n{6}', re.DOTALL)
69
70
    @asyncio.coroutine
71
    def get_oneliner(self, from_html=None):
72
        if from_html is None:
73
            text = yield from util.get_markup(self._url)
74
        else:
75
            text = from_html
76
77
        parsed_content = bs4.BeautifulSoup(text, 'html.parser')
78
79
        raw_joke = parsed_content.find_all('p')[6].get_text()
80
        match = self._joke_regex.search(raw_joke)
81
        return match.group(1).strip()
82
83
    @asyncio.coroutine
84
    def get(self):
85
        result = yield from self.get_oneliner()
86
        return result
87
88
89
class Square:
90
    @asyncio.coroutine
91
    def get(self, string_literal):
92
        if len(string_literal) > 31:
93
            raise StringLengthError
94
95
        if not string_literal:
96
            raise EmptyStringError
97
98
        lookup_string = string_literal + string_literal[:-1][::-1]
99
100
        string_length = len(string_literal)
101
        string_list = []
102
103
        for idx in range(string_length):
104
            row_string = lookup_string[idx:string_length + idx]
105
            string_list.append(' '.join(row_string))
106
107
        square = '\n'.join(string_list).upper()
108
109
        return '```\n{}\n```'.format(square)
110
111
112
class Imgur:
113
    def __init__(self, id_length=5):
114
        self.id_length = id_length
115
116
        self._valid_characters = string.ascii_letters + string.digits
117
        self._removed_url = 'https://i.imgur.com/removed.png'
118
        self._base_url = 'https://i.imgur.com/{}.png'
119
120
    @asyncio.coroutine
121
    def get(self):
122
        while True:
123
            image_id = ''.join(random.choice(self._valid_characters)
124
                               for _ in range(self.id_length))
125
            image_url = self._base_url.format(image_id)
126
127
            r = None
0 ignored issues
show
Coding Style Naming introduced by
The name r does not conform to the variable naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
128
            try:
129
                r = yield from aiohttp.get(image_url)
0 ignored issues
show
Coding Style Naming introduced by
The name r does not conform to the variable naming conventions ([a-z_][a-z0-9_]{2,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
130
            except aiohttp.errors.ClientResponseError:
131
                continue
132
            finally:
133
                if r is not None:
134
                    r.close()
135
136
            if r.url != self._removed_url:
137
                return image_url
138
139
140
class Insult:
141
    def __init__(self):
142
        self._insult_url = 'http://www.insultgenerator.org/'
143
144
    @asyncio.coroutine
145
    def get(self, from_html=None):
146
        if from_html is None:
147
            text = yield from util.get_markup(self._insult_url)
148
        else:
149
            text = from_html
150
151
        parsed_insult = bs4.BeautifulSoup(text, 'html.parser')
152
        return parsed_insult.find('div', class_='wrap').get_text().lstrip()
153
154
155
class Roll:
156
    def __init__(self, dice_limit=5000):
157
        self._dice_limit = dice_limit
158
159
    @asyncio.coroutine
160
    def get(self, dice=None):
161
        if not dice:
162
            return str(random.randint(1, 6))
163
164
        dice = dice.lower()
165
166
        try:
167
            rolls, limit = map(int, dice.split('d'))
168
        except ValueError:
169
            dice = int(dice)
170
            if dice < 2:
171
                raise
172
            return str(random.randint(1, dice))
173
174
        if rolls < 1 or limit < 2:
175
            raise ValueError
176
177
        num_limit_digits = int(len(str(limit)))
178
        if rolls * num_limit_digits > self._dice_limit:
179
            raise StringLengthError
180
181
        return ', '.join(str(random.randint(1, limit))
182
                         for _ in range(rolls))
183