SpiffyTitles: fixes #29 - adds imgur album handler
Major refactoring to accommodate multiple imgur handlers Replaces single quotes with double to maintain consistency Updates README
This commit is contained in:
parent
1d053b4cb0
commit
329111c018
10
README.md
10
README.md
|
|
@ -41,12 +41,20 @@ Example output:
|
|||
|
||||
`imgurTemplate` - This is the template used when showing information about an [imgur](https://imgur.com) link.
|
||||
|
||||
Default value: `^{%if section %} [{{section}}] {%endif %}{%if title %}{{title}} :: {% endif %}{{type}} {{width}}x{{height}} {{file_size}} :: {{view_count}} views :: {%if nsfw == None %}not sure if safe for work{% elif nsfw == True %}not safe for work!{% else %}safe for work{% endif %}`
|
||||
Default value: `^{%if section %} [{{section}}] {% endif -%}{%- if title -%} {{title}} :: {% endif %}{{type}} {{width}}x{{height}} {{file_size}} :: {{view_count}} views :: {%if nsfw == None %}not sure if safe for work{% elif nsfw == True %}not safe for work!{% else %}safe for work{% endif %}`
|
||||
|
||||
Example output:
|
||||
|
||||
^ [pics] He really knows nothing... :: image/jpeg 700x1575 178.8KiB :: 809 views :: safe for work
|
||||
|
||||
`imgurAlbumTemplate` - This is the template used when showing information about an imgur album link.
|
||||
|
||||
Default value: `^{%if section %} [{{section}}] {% endif -%}{%- if title -%} {{title}} :: {% endif %}{{image_count}} images :: {{view_count}} views :: {%if nsfw == None %}not sure if safe for work{% elif nsfw == True %}not safe for work!{% else %}safe for work{% endif %}`
|
||||
|
||||
Example output:
|
||||
|
||||
^ [compsci] Regex Fractals :: 33 images :: 21,453 views :: safe for work
|
||||
|
||||
Notes on the imgur handler:
|
||||
|
||||
- You'll need a [register an application with imgur](https://api.imgur.com/oauth2/addclient)
|
||||
|
|
|
|||
|
|
@ -75,9 +75,12 @@ conf.registerGlobalValue(SpiffyTitles, 'imgurClientSecret',
|
|||
registry.String("", _("""imgur client secret""")))
|
||||
|
||||
conf.registerGlobalValue(SpiffyTitles, 'imgurTemplate',
|
||||
registry.String("^ {%if section %}[{{section}}] {%endif %}{%if title %}{{title}} :: {% endif %}{{type}} {{width}}x{{height}} {{file_size}} :: {{view_count}} views :: {%if nsfw == None %}not sure if safe for work{% elif nsfw == True %}not safe for work!{% else %}safe for work{% endif %}", _("""imgur template""")))
|
||||
registry.String("^{%if section %} [{{section}}] {% endif -%}{%- if title -%} {{title}} :: {% endif %}{{type}} {{width}}x{{height}} {{file_size}} :: {{view_count}} views :: {%if nsfw == None %}not sure if safe for work{% elif nsfw == True %}not safe for work!{% else %}safe for work{% endif %}", _("""imgur template""")))
|
||||
|
||||
|
||||
conf.registerGlobalValue(SpiffyTitles, 'imgurAlbumTemplate',
|
||||
registry.String("^{%if section %} [{{section}}] {% endif -%}{%- if title -%} {{title}} :: {% endif %}{{image_count}} images :: {{view_count}} views :: {%if nsfw == None %}not sure if safe for work{% elif nsfw == True %}not safe for work!{% else %}safe for work{% endif %}", _("""imgur template""")))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
225
plugin.py
225
plugin.py
|
|
@ -24,7 +24,7 @@ from jinja2 import Template
|
|||
|
||||
try:
|
||||
from supybot.i18n import PluginInternationalization
|
||||
_ = PluginInternationalization('SpiffyTitles')
|
||||
_ = PluginInternationalization("SpiffyTitles")
|
||||
except ImportError:
|
||||
# Placeholder that allows to run the plugin on a bot
|
||||
# without the i18n module
|
||||
|
|
@ -33,7 +33,7 @@ except ImportError:
|
|||
class SpiffyTitles(callbacks.Plugin):
|
||||
"""Displays link titles when posted in a channel"""
|
||||
threaded = True
|
||||
callBefore = ['Web']
|
||||
callBefore = ["Web"]
|
||||
link_cache = {}
|
||||
handlers = {}
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ class SpiffyTitles(callbacks.Plugin):
|
|||
self.__parent = super(SpiffyTitles, self)
|
||||
self.__parent.__init__(irc)
|
||||
|
||||
self.link_throttle_in_seconds = self.registryValue('cooldownInSeconds')
|
||||
self.link_throttle_in_seconds = self.registryValue("cooldownInSeconds")
|
||||
|
||||
"""
|
||||
Check if imgur client id or secret are set, and if so initialize
|
||||
|
|
@ -51,8 +51,11 @@ class SpiffyTitles(callbacks.Plugin):
|
|||
imgur_client_secret = self.registryValue("imgurClientSecret")
|
||||
|
||||
if imgur_client_id and imgur_client_secret:
|
||||
# Set handler
|
||||
self.handlers["i.imgur.com"] = self.handler_imgur
|
||||
# Images mostly
|
||||
self.handlers["i.imgur.com"] = self.handler_imgur_image
|
||||
|
||||
# Albums, galleries, etc
|
||||
self.handlers["imgur.com"] = self.handler_imgur
|
||||
|
||||
# Initialize API client
|
||||
try:
|
||||
|
|
@ -65,10 +68,7 @@ class SpiffyTitles(callbacks.Plugin):
|
|||
except ImportError, e:
|
||||
self.log.error("SpiffyTitles ImportError: %s" % str(e))
|
||||
|
||||
self.handlers["youtube.com"] = self.handler_youtube
|
||||
self.handlers["www.youtube.com"] = self.handler_youtube
|
||||
self.handlers["youtu.be"] = self.handler_youtube
|
||||
self.handlers["m.youtube.com"] = self.handler_youtube
|
||||
self.add_youtube_handlers()
|
||||
|
||||
def doPrivmsg(self, irc, msg):
|
||||
"""
|
||||
|
|
@ -92,45 +92,53 @@ class SpiffyTitles(callbacks.Plugin):
|
|||
|
||||
info = urlparse(url)
|
||||
|
||||
if info:
|
||||
domain = info.netloc
|
||||
is_ignored = self.is_ignored_domain(domain)
|
||||
|
||||
if is_ignored:
|
||||
self.log.info("SpiffyTitles: ignoring url due to pattern match: %s" % (url))
|
||||
return
|
||||
|
||||
# Check if we've seen this link lately
|
||||
if url in self.link_cache:
|
||||
link_timestamp = self.link_cache[url]
|
||||
|
||||
seconds = (now - link_timestamp).total_seconds()
|
||||
throttled = seconds < self.link_throttle_in_seconds
|
||||
else:
|
||||
throttled = False
|
||||
|
||||
if throttled:
|
||||
self.log.info("SpiffyTitles: %s ignored; throttle: it has been %s seconds since last post" % (url, seconds))
|
||||
return
|
||||
|
||||
# Update link cache now that we know it's not an ignored link
|
||||
self.link_cache[url] = now
|
||||
|
||||
try:
|
||||
handler = self.handlers[domain]
|
||||
title = handler(url, info, irc)
|
||||
except KeyError:
|
||||
title = self.handler_default(url, info, irc)
|
||||
else:
|
||||
self.log.error("SpiffyTitles: unable to determine domain from url %s" % (url))
|
||||
title = self.handler_default(url, irc)
|
||||
domain = info.netloc
|
||||
is_ignored = self.is_ignored_domain(domain)
|
||||
|
||||
if title is not None:
|
||||
if is_ignored:
|
||||
self.log.info("SpiffyTitles: ignoring url due to pattern match: %s" % (url))
|
||||
return
|
||||
|
||||
# Check if we"ve seen this link lately
|
||||
if url in self.link_cache:
|
||||
link_timestamp = self.link_cache[url]
|
||||
|
||||
seconds = (now - link_timestamp).total_seconds()
|
||||
throttled = seconds < self.link_throttle_in_seconds
|
||||
else:
|
||||
throttled = False
|
||||
|
||||
if throttled:
|
||||
self.log.info("SpiffyTitles: %s ignored; throttle: it has been %s seconds since last post" % (url, seconds))
|
||||
return
|
||||
|
||||
# Update link cache now that we know it"s not an ignored link
|
||||
self.link_cache[url] = now
|
||||
|
||||
if domain in self.handlers:
|
||||
handler = self.handlers[domain]
|
||||
title = handler(url, info)
|
||||
else:
|
||||
title = self.handler_default(url, info)
|
||||
|
||||
if title is not None and title:
|
||||
self.log.info("SpiffyTitles: title found: %s" % (title))
|
||||
|
||||
formatted_title = self.get_formatted_title(title)
|
||||
|
||||
irc.reply(formatted_title)
|
||||
else:
|
||||
self.log.error("SpiffyTitles: could not get a title for %s" % (url))
|
||||
|
||||
def add_youtube_handlers(self):
|
||||
"""
|
||||
Adds handlers for Youtube videos. The handler is matched based on the
|
||||
domain used in the URL.
|
||||
"""
|
||||
self.handlers["youtube.com"] = self.handler_youtube
|
||||
self.handlers["www.youtube.com"] = self.handler_youtube
|
||||
self.handlers["youtu.be"] = self.handler_youtube
|
||||
self.handlers["m.youtube.com"] = self.handler_youtube
|
||||
|
||||
def is_channel_allowed(self, channel):
|
||||
"""
|
||||
|
|
@ -183,7 +191,7 @@ class SpiffyTitles(callbacks.Plugin):
|
|||
except re.Error:
|
||||
self.log.error("SpiffyTitles: invalid regular expression: %s" % (pattern))
|
||||
|
||||
def get_video_id_from_url(self, url, info, irc):
|
||||
def get_video_id_from_url(self, url, info):
|
||||
"""
|
||||
Get YouTube video ID from URL
|
||||
"""
|
||||
|
|
@ -206,13 +214,13 @@ class SpiffyTitles(callbacks.Plugin):
|
|||
except IndexError, e:
|
||||
self.log.error("SpiffyTitles: error getting video id from %s (%s)" % (url, str(e)))
|
||||
|
||||
def handler_youtube(self, url, domain, irc):
|
||||
def handler_youtube(self, url, domain):
|
||||
"""
|
||||
Uses the Youtube API to provide additional meta data about
|
||||
Youtube Video links posted.
|
||||
"""
|
||||
self.log.info("SpiffyTitles: calling Youtube handler for %s" % (url))
|
||||
video_id = self.get_video_id_from_url(url, domain, irc)
|
||||
video_id = self.get_video_id_from_url(url, domain)
|
||||
yt_template = Template(self.registryValue("youtubeTitleTemplate"))
|
||||
title = ""
|
||||
|
||||
|
|
@ -234,13 +242,13 @@ class SpiffyTitles(callbacks.Plugin):
|
|||
if response:
|
||||
try:
|
||||
data = response["data"]
|
||||
title = data['title']
|
||||
rating = str(round(data['rating'], 2))
|
||||
view_count = '{:,}'.format(int(data['viewCount']))
|
||||
duration_seconds = int(data['duration'])
|
||||
title = data["title"]
|
||||
rating = str(round(data["rating"], 2))
|
||||
view_count = "{:,}".format(int(data["viewCount"]))
|
||||
duration_seconds = int(data["duration"])
|
||||
|
||||
"""
|
||||
#23 - If duration is zero, then it's a LIVE video
|
||||
#23 - If duration is zero, then it"s a LIVE video
|
||||
"""
|
||||
if duration_seconds > 0:
|
||||
m, s = divmod(duration_seconds, 60)
|
||||
|
|
@ -277,9 +285,9 @@ class SpiffyTitles(callbacks.Plugin):
|
|||
else:
|
||||
self.log.info("SpiffyTitles: falling back to default handler")
|
||||
|
||||
return self.handler_default(url, domain, irc)
|
||||
return self.handler_default(url, domain)
|
||||
|
||||
def handler_default(self, url, domain, irc):
|
||||
def handler_default(self, url, domain):
|
||||
"""
|
||||
Default handler for websites
|
||||
"""
|
||||
|
|
@ -295,22 +303,82 @@ class SpiffyTitles(callbacks.Plugin):
|
|||
|
||||
return title_template
|
||||
|
||||
def handler_imgur(self, url, info, irc):
|
||||
def handler_imgur(self, url, info):
|
||||
"""
|
||||
Queries imgur API for additional information about imgur links
|
||||
Queries imgur API for additional information about imgur links.
|
||||
|
||||
This handler is for any imgur.com domain.
|
||||
"""
|
||||
is_album = info.path.startswith("/a/")
|
||||
is_gallery = info.path.startswith("/gallery/")
|
||||
result = None
|
||||
|
||||
if is_album:
|
||||
result = self.handler_imgur_album(url, info)
|
||||
else:
|
||||
result = self.handler_default(url, info)
|
||||
|
||||
return result
|
||||
|
||||
def handler_imgur_album(self, url, info):
|
||||
"""
|
||||
Handles retrieving information about albums from the imgur API.
|
||||
|
||||
imgur provides the following information about albums: https://api.imgur.com/models/album
|
||||
"""
|
||||
from imgurpython.helpers.error import ImgurClientRateLimitError
|
||||
from imgurpython.helpers.error import ImgurClientError
|
||||
|
||||
album_id = info.path.split("/a/")[1]
|
||||
|
||||
""" If there is a query string appended, remove it """
|
||||
if "?" in album_id:
|
||||
album_id = album_id.split("?")[0]
|
||||
|
||||
if album_id:
|
||||
self.log.info("SpiffyTitles: found imgur album id %s" % (album_id))
|
||||
|
||||
try:
|
||||
album = self.imgur_client.get_album(album_id)
|
||||
|
||||
if album:
|
||||
imgur_album_template = Template(self.registryValue("imgurAlbumTemplate"))
|
||||
compiled_template = imgur_album_template.render({
|
||||
"title": album.title,
|
||||
"section": album.section,
|
||||
"view_count": "{:,}".format(album.views),
|
||||
"image_count": "{:,}".format(album.images_count),
|
||||
"nsfw": album.nsfw
|
||||
})
|
||||
|
||||
return compiled_template
|
||||
else:
|
||||
self.log.error("SpiffyTitles: imgur album API returned unexpected results!")
|
||||
|
||||
except ImgurClientRateLimitError as e:
|
||||
self.log.error("SpiffyTitles: imgur rate limit error: %s" % (e.error_message))
|
||||
except ImgurClientError as e:
|
||||
self.log.error("SpiffyTitles: imgur client error: %s" % (e.error_message))
|
||||
else:
|
||||
self.log.info("SpiffyTitles: unable to determine album id for %s" % (url))
|
||||
|
||||
def handler_imgur_image(self, url, info):
|
||||
"""
|
||||
Handles retrieving information about images from the imgur API.
|
||||
|
||||
This handler is only run when the domain is i.imgur.com which is usually
|
||||
just images, except in the case of gifv - which is a HTML file which has
|
||||
a title. The latter case is why there are fallbacks here.
|
||||
|
||||
The path comes in this form: /image_id.extension so strip off the left
|
||||
forward slash and then split by period to get the image id
|
||||
forward slash and then split by period to get the image id.
|
||||
"""
|
||||
from imgurpython.helpers.error import ImgurClientRateLimitError
|
||||
from imgurpython.helpers.error import ImgurClientError
|
||||
|
||||
path = info.path.lstrip("/")
|
||||
image_id = path.split(".")[0]
|
||||
|
||||
self.log.info("SpiffyTitles: image id found: %s" % (image_id))
|
||||
title = None
|
||||
|
||||
if image_id:
|
||||
try:
|
||||
|
|
@ -325,41 +393,35 @@ class SpiffyTitles(callbacks.Plugin):
|
|||
"nsfw": image.nsfw,
|
||||
"width": image.width,
|
||||
"height": image.height,
|
||||
"view_count": '{:,}'.format(image.views),
|
||||
"view_count": "{:,}".format(image.views),
|
||||
"file_size": readable_file_size,
|
||||
"section": image.section
|
||||
})
|
||||
|
||||
return compiled_template
|
||||
title = compiled_template
|
||||
else:
|
||||
self.log.error("SpiffyTitles: imgur API returned unexpected results!")
|
||||
|
||||
# Fall back to default handler
|
||||
self.handler_default(url, info, irc)
|
||||
|
||||
except ImgurClientRateLimitError as e:
|
||||
self.log.error("SpiffyTitles: imgur rate limit error: %s" % (e.error_message))
|
||||
|
||||
# Fall back to default handler
|
||||
self.handler_default(url, info, irc)
|
||||
|
||||
except ImgurClientError as e:
|
||||
self.log.error("SpiffyTitles: imgur client error: %s" % (e.error_message))
|
||||
|
||||
# Fall back to default handler
|
||||
self.handler_default(url, info, irc)
|
||||
else:
|
||||
self.log.error("SpiffyTitles: error retrieving image id for %s" % (url))
|
||||
|
||||
if title is not None:
|
||||
return title
|
||||
else:
|
||||
return self.handler_default(url, info)
|
||||
|
||||
def get_readable_file_size(self, num, suffix='B'):
|
||||
def get_readable_file_size(self, num, suffix="B"):
|
||||
"""
|
||||
Returns human readable file size
|
||||
"""
|
||||
for unit in ['','Ki','Mi','Gi','Ti','Pi','Ei','Zi']:
|
||||
for unit in ["","Ki","Mi","Gi","Ti","Pi","Ei","Zi"]:
|
||||
if abs(num) < 1024.0:
|
||||
return "%3.1f%s%s" % (num, unit, suffix)
|
||||
num /= 1024.0
|
||||
return "%.1f%s%s" % (num, 'Yi', suffix)
|
||||
return "%.1f%s%s" % (num, "Yi", suffix)
|
||||
|
||||
def get_formatted_title(self, title):
|
||||
"""
|
||||
|
|
@ -411,9 +473,9 @@ class SpiffyTitles(callbacks.Plugin):
|
|||
}
|
||||
request = requests.get(url, headers=headers)
|
||||
|
||||
ok = request.status_code == requests.codes.ok
|
||||
self.log.info("SpiffyTitles: requesting %s" % (url))
|
||||
|
||||
if ok:
|
||||
if request.status_code == requests.codes.ok:
|
||||
# Check the content type which comes in the format: "text/html; charset=UTF-8"
|
||||
content_type = request.headers.get("content-type").split(";")[0].strip()
|
||||
acceptable_types = self.registryValue("mimeTypes")
|
||||
|
|
@ -424,7 +486,11 @@ class SpiffyTitles(callbacks.Plugin):
|
|||
if mime_type_acceptable:
|
||||
text = request.content
|
||||
|
||||
return text
|
||||
if text:
|
||||
return text
|
||||
else:
|
||||
self.log.info("SpiffyTitles: empty content from %s" % (url))
|
||||
|
||||
else:
|
||||
self.log.debug("SpiffyTitles: unacceptable mime type %s for url %s" % (content_type, url))
|
||||
else:
|
||||
|
|
@ -441,11 +507,17 @@ class SpiffyTitles(callbacks.Plugin):
|
|||
self.log.error("SpiffyTitles InvalidURL: %s" % (str(e)))
|
||||
|
||||
def get_user_agent(self):
|
||||
"""
|
||||
Returns a random user agent from the ones available
|
||||
"""
|
||||
agents = self.registryValue("userAgents")
|
||||
|
||||
return random.choice(agents)
|
||||
|
||||
def get_url_from_message(self, input):
|
||||
"""
|
||||
Find the first string that looks like a URL from the message
|
||||
"""
|
||||
url_re = self.registryValue("urlRegularExpression")
|
||||
match = re.search(url_re, input)
|
||||
|
||||
|
|
@ -454,5 +526,4 @@ class SpiffyTitles(callbacks.Plugin):
|
|||
|
||||
Class = SpiffyTitles
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
|
||||
|
|
|
|||
Loading…
Reference in New Issue