Skip to content

Commit a926189

Browse files
authored
Merge pull request CloudBotIRC#138 from linuxdaemon/gonzobot+reddit-url-fix
Fix formatting of reddit post url
2 parents 51b13d5 + 2a32bc1 commit a926189

2 files changed

Lines changed: 54 additions & 43 deletions

File tree

plugins/reddit.py

Lines changed: 53 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,44 @@
1-
import asyncio
2-
import functools
31
import random
42
import re
5-
import urllib.parse
63
from datetime import datetime
74

85
import requests
6+
from yarl import URL
97

108
from cloudbot import hook
119
from cloudbot.util import timeformat, formatting
1210

13-
reddit_re = re.compile(r'.*(((www\.)?reddit\.com/r|redd\.it)[^ ]+)', re.I)
11+
reddit_re = re.compile(
12+
r"""
13+
https? # Scheme
14+
://
1415
15-
base_url = "http://reddit.com/r/{}/.json"
16-
short_url = "http://redd.it/{}"
16+
# Domain
17+
(?:
18+
redd\.it|
19+
(?:www\.)?reddit\.com/r
20+
)
21+
22+
(?:/(?:[A-Za-z0-9!$&-.:;=@_~\u00A0-\u10FFFD]|%[A-F0-9]{2})*)* # Path
23+
24+
(?:\?(?:[A-Za-z0-9!$&-;=@_~\u00A0-\u10FFFD]|%[A-F0-9]{2})*)? # Query
25+
""",
26+
re.IGNORECASE | re.VERBOSE
27+
)
28+
29+
base_url = "https://reddit.com/r/{}"
30+
short_url = "https://redd.it/{}"
31+
32+
33+
def api_request(url, bot):
34+
"""
35+
:type url: yarl.URL
36+
:type bot: cloudbot.bot.CloudBot
37+
"""
38+
url = url.with_query("").with_scheme("https") / ".json"
39+
r = requests.get(str(url), headers={'User-Agent': bot.user_agent})
40+
r.raise_for_status()
41+
return r.json()
1742

1843

1944
def format_output(item, show_url=False):
@@ -40,72 +65,57 @@ def format_output(item, show_url=False):
4065
" - \x02{author}\x02, {timesince} ago{warning}".format(**item)
4166

4267

43-
@hook.regex(reddit_re)
68+
@hook.regex(reddit_re, singlethread=True)
4469
def reddit_url(match, bot):
45-
url = match.group(1)
46-
if "redd.it" in url:
47-
url = "http://" + url
48-
response = requests.get(url)
49-
url = response.url + "/.json"
50-
if not urllib.parse.urlparse(url).scheme:
51-
url = "http://" + url + "/.json"
52-
53-
# the reddit API gets grumpy if we don't include headers
54-
headers = {'User-Agent': bot.user_agent}
55-
r = requests.get(url, headers=headers)
56-
r.raise_for_status()
57-
if r.status_code != 200:
58-
return
59-
data = r.json()
60-
assert isinstance(data, list), "Reddit API returned data in an unknown format"
70+
url = match.group()
71+
url = URL(url).with_scheme("https")
72+
73+
if url.host.endswith("redd.it"):
74+
response = requests.get(url, headers={'User-Agent': bot.user_agent})
75+
response.raise_for_status()
76+
url = URL(response.url).with_scheme("https")
77+
78+
data = api_request(url, bot)
6179
item = data[0]["data"]["children"][0]["data"]
6280

6381
return format_output(item)
6482

6583

66-
@asyncio.coroutine
67-
@hook.command(autohelp=False)
68-
def reddit(text, bot, loop, reply):
69-
"""<subreddit> [n] - gets a random post from <subreddit>, or gets the [n]th post in the subreddit"""
84+
@hook.command(autohelp=False, singlethread=True)
85+
def reddit(text, bot, reply):
86+
"""[subreddit] [n] - gets a random post from <subreddit>, or gets the [n]th post in the subreddit"""
7087
id_num = None
71-
headers = {'User-Agent': bot.user_agent}
7288

7389
if text:
7490
# clean and split the input
7591
parts = text.lower().strip().split()
92+
url = base_url.format(parts.pop(0).strip())
7693

7794
# find the requested post number (if any)
78-
if len(parts) > 1:
79-
url = base_url.format(parts[0].strip())
95+
if parts:
8096
try:
81-
id_num = int(parts[1]) - 1
97+
id_num = int(parts[0]) - 1
8298
except ValueError:
8399
return "Invalid post number."
84-
else:
85-
url = base_url.format(parts[0].strip())
86100
else:
87-
url = "http://reddit.com/.json"
101+
url = "https://reddit.com"
88102

89103
try:
90-
# Again, identify with Reddit using an User Agent, otherwise get a 429
91-
inquiry = yield from loop.run_in_executor(None, functools.partial(requests.get, url, headers=headers))
92-
inquiry.raise_for_status()
93-
if inquiry.status_code != 200:
94-
return "r/{} either does not exist or is private.".format(text)
95-
data = inquiry.json()
104+
data = api_request(URL(url), bot)
96105
except Exception as e:
97106
reply("Error: " + str(e))
98107
raise
108+
99109
data = data["data"]["children"]
100110

101111
# get the requested/random post
102112
if id_num is not None:
103113
try:
104-
item = data[id_num]["data"]
114+
item = data[id_num]
105115
except IndexError:
106116
length = len(data)
107117
return "Invalid post number. Number must be between 1 and {}.".format(length)
108118
else:
109-
item = random.choice(data)["data"]
119+
item = random.choice(data)
110120

111-
return format_output(item, show_url=True)
121+
return format_output(item["data"], show_url=True)

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ pyenchant
1717
pythonwhois
1818
imgurpython
1919
isodate
20+
yarl

0 commit comments

Comments
 (0)