YouTube: remove dependencies, simplify, cleanup

This commit is contained in:
oddluck 2020-05-21 05:01:21 -04:00
parent 2dfc2068c3
commit c14b0852a7
5 changed files with 104 additions and 118 deletions

View File

@ -3,3 +3,9 @@ Search for YouTube videos and return link + info.
Enable the [YouTube Data API](https://console.developers.google.com/apis/library/youtube.googleapis.com). Set your [API Key](https://console.cloud.google.com/apis/credentials) using the command below. Enable the [YouTube Data API](https://console.developers.google.com/apis/library/youtube.googleapis.com). Set your [API Key](https://console.cloud.google.com/apis/credentials) using the command below.
`config plugins.youtube.developerkey your_key_here` `config plugins.youtube.developerkey your_key_here`
`config plugins.youtube.template` - set the reply template.
Default template:
`$logo :: $link :: $title :: Duration: $duration :: Views: $views :: Uploader: $uploader :: Uploaded: $published :: $likes likes :: $dislikes dislikes :: $favorites favorites :: $comments comments`

View File

@ -37,7 +37,7 @@ import supybot.world as world
# Use this for the version of this plugin. You may wish to put a CVS keyword # Use this for the version of this plugin. You may wish to put a CVS keyword
# in here if you're keeping the plugin in CVS or some similar system. # in here if you're keeping the plugin in CVS or some similar system.
__version__ = "2020.02.24+git" __version__ = "2020.05.21+git"
# XXX Replace this with an appropriate author or supybot.Author instance. # XXX Replace this with an appropriate author or supybot.Author instance.
__author__ = supybot.Author("oddluck", "oddluck", "oddluck@riseup.net") __author__ = supybot.Author("oddluck", "oddluck", "oddluck@riseup.net")

View File

@ -91,9 +91,9 @@ conf.registerChannelValue(
YouTube, YouTube,
"template", "template",
registry.String( registry.String(
"{{logo}} :: {{link}} :: {{title}} :: Duration: {{duration}} :: Views: {{views}} " "$logo :: $link :: $title :: Duration: $duration :: Views: $views :: Uploader:"
":: Uploader: {{uploader}} :: Uploaded: {{published}} :: {{likes}} likes :: " " $uploader :: Uploaded: $published :: $likes likes :: $dislikes dislikes ::"
"{{dislikes}} dislikes :: {{favorites}} favorites :: {{comments}} comments", " $favorites favorites :: $comments comments",
_("""Template used for search result replies"""), _("""Template used for search result replies"""),
), ),
) )

View File

@ -35,11 +35,8 @@ import supybot.ircutils as ircutils
import supybot.ircmsgs as ircmsgs import supybot.ircmsgs as ircmsgs
import supybot.callbacks as callbacks import supybot.callbacks as callbacks
import supybot.log as log import supybot.log as log
import requests from string import Template
import pendulum import datetime, json, re
import json
from jinja2 import Template
from urllib.parse import urlencode
try: try:
from supybot.i18n import PluginInternationalization from supybot.i18n import PluginInternationalization
@ -56,10 +53,10 @@ class YouTube(callbacks.Plugin):
threaded = True threaded = True
def dosearch(self, query): def dosearch(self, query, channel):
apikey = self.registryValue("developerKey") apikey = self.registryValue("developerKey")
safe_search = self.registryValue("safeSearch", dynamic.channel) safe_search = self.registryValue("safeSearch", channel)
sort_order = self.registryValue("sortOrder", dynamic.channel) sort_order = self.registryValue("sortOrder", channel)
video_id = None video_id = None
opts = { opts = {
"q": query, "q": query,
@ -71,19 +68,17 @@ class YouTube(callbacks.Plugin):
"type": "video", "type": "video",
} }
api_url = "https://www.googleapis.com/youtube/v3/search?{0}".format( api_url = "https://www.googleapis.com/youtube/v3/search?{0}".format(
urlencode(opts) utils.web.urlencode(opts)
) )
try: try:
log.debug("YouTube: requesting %s" % (api_url)) log.debug("YouTube: requesting %s" % (api_url))
request = requests.get(api_url, timeout=10) request = utils.web.getUrl(api_url).decode()
response = json.loads(request.content) response = json.loads(request)
video_id = response["items"][0]["id"]["videoId"] video_id = response["items"][0]["id"]["videoId"]
except Exception: except:
log.error( log.error(
"YouTube: YouTube API HTTP %s: %s" "YouTube: Error retrieving data from API: %s" % request.content.decode()
% (request.status_code, request.content.decode())
) )
pass
return video_id return video_id
def get_duration_from_seconds(self, duration_seconds): def get_duration_from_seconds(self, duration_seconds):
@ -101,21 +96,34 @@ class YouTube(callbacks.Plugin):
4 minutes and 41 seconds. This method returns the total seconds 4 minutes and 41 seconds. This method returns the total seconds
so that the duration can be parsed as usual. so that the duration can be parsed as usual.
""" """
duration = pendulum.parse(input) regex = re.compile(
return duration.total_seconds() r"""
(?P<sign> -?) P
(?:(?P<years> \d+) Y)?
(?:(?P<months> \d+) M)?
(?:(?P<days> \d+) D)?
(?: T
(?:(?P<hours> \d+) H)?
(?:(?P<minutes>\d+) M)?
(?:(?P<seconds>\d+) S)?
)?
""",
re.VERBOSE,
)
duration = regex.match(input).groupdict(0)
delta = datetime.timedelta(
hours=int(duration["hours"]),
minutes=int(duration["minutes"]),
seconds=int(duration["seconds"]),
)
return delta.total_seconds()
def get_published_date(self, date): def get_youtube_logo(self, channel):
date = pendulum.parse(date, strict=False) use_bold = self.registryValue("useBold", channel)
date = pendulum.datetime(date.year, date.month, date.day)
date = date.to_date_string()
return date
def get_youtube_logo(self):
use_bold = self.registryValue("useBold", dynamic.channel)
if use_bold: if use_bold:
yt_logo = "{0}\x0F\x02".format(self.registryValue("logo", dynamic.channel)) yt_logo = "{0}\x0F\x02".format(self.registryValue("logo", channel))
else: else:
yt_logo = "{0}\x0F".format(self.registryValue("logo", dynamic.channel)) yt_logo = "{0}\x0F".format(self.registryValue("logo", channel))
return yt_logo return yt_logo
def yt(self, irc, msg, args, query): def yt(self, irc, msg, args, query):
@ -126,11 +134,12 @@ class YouTube(callbacks.Plugin):
if not apikey: if not apikey:
irc.reply("Error: You need to set an API key to use this plugin.") irc.reply("Error: You need to set an API key to use this plugin.")
return return
channel = msg.channel template = self.registryValue("template", msg.channel)
yt_template = Template(self.registryValue("template", channel)) template = template.replace("{{", "$").replace("}}", "")
template = Template(template)
response = None response = None
title = None title = None
video_id = self.dosearch(query) video_id = self.dosearch(query, msg.channel)
if video_id: if video_id:
log.debug("YouTube: got video id: %s" % video_id) log.debug("YouTube: got video id: %s" % video_id)
opts = { opts = {
@ -139,20 +148,16 @@ class YouTube(callbacks.Plugin):
"key": apikey, "key": apikey,
"id": video_id, "id": video_id,
} }
opts = urlencode(opts) opts = utils.web.urlencode(opts)
api_url = "https://www.googleapis.com/youtube/v3/videos?%s" % (opts) api_url = "https://www.googleapis.com/youtube/v3/videos?%s" % (opts)
log.debug("YouTube: requesting %s" % (api_url)) log.debug("YouTube: requesting %s" % (api_url))
request = requests.get(api_url, timeout=10) request = utils.web.getUrl(api_url).decode()
ok = request.status_code == requests.codes.ok response = json.loads(request)
if ok:
response = json.loads(request.content)
if response:
try: try:
if response["pageInfo"]["totalResults"] > 0: if response["pageInfo"]["totalResults"] > 0:
items = response["items"] items = response["items"]
video = items[0] video = items[0]
snippet = video["snippet"] snippet = video["snippet"]
title = snippet["title"]
statistics = video["statistics"] statistics = video["statistics"]
view_count = 0 view_count = 0
like_count = 0 like_count = 0
@ -164,35 +169,22 @@ class YouTube(callbacks.Plugin):
if "likeCount" in statistics: if "likeCount" in statistics:
like_count = "{:,}".format(int(statistics["likeCount"])) like_count = "{:,}".format(int(statistics["likeCount"]))
if "dislikeCount" in statistics: if "dislikeCount" in statistics:
dislike_count = "{:,}".format( dislike_count = "{:,}".format(int(statistics["dislikeCount"]))
int(statistics["dislikeCount"])
)
if "favoriteCount" in statistics: if "favoriteCount" in statistics:
favorite_count = "{:,}".format( favorite_count = "{:,}".format(int(statistics["favoriteCount"]))
int(statistics["favoriteCount"])
)
if "commentCount" in statistics: if "commentCount" in statistics:
comment_count = "{:,}".format( comment_count = "{:,}".format(int(statistics["commentCount"]))
int(statistics["commentCount"])
)
channel_title = snippet["channelTitle"] channel_title = snippet["channelTitle"]
video_duration = video["contentDetails"]["duration"] video_duration = video["contentDetails"]["duration"]
duration_seconds = self.get_total_seconds_from_duration( duration_seconds = self.get_total_seconds_from_duration(
video_duration video_duration
) )
if duration_seconds > 0: if duration_seconds > 0:
duration = self.get_duration_from_seconds( duration = self.get_duration_from_seconds(duration_seconds)
duration_seconds
)
else: else:
duration = "LIVE" duration = "LIVE"
published = snippet["publishedAt"] results = {
published = self.get_published_date(published) "title": snippet["title"],
yt_logo = self.get_youtube_logo()
link = "https://youtu.be/%s" % (video_id)
compiled_template = yt_template.render(
{
"title": title,
"duration": duration, "duration": duration,
"views": view_count, "views": view_count,
"likes": like_count, "likes": like_count,
@ -200,30 +192,23 @@ class YouTube(callbacks.Plugin):
"comments": comment_count, "comments": comment_count,
"favorites": favorite_count, "favorites": favorite_count,
"uploader": channel_title, "uploader": channel_title,
"link": link, "link": "https://youtu.be/%s" % (video_id),
"published": published, "published": snippet["publishedAt"].split("T")[0],
"logo": yt_logo, "logo": self.get_youtube_logo(msg.channel),
} }
) title = template.safe_substitute(results)
title = compiled_template
else: else:
log.debug( log.debug("YouTube: video appears to be private; no results!")
"YouTube: video appears to be private; no results!" except:
)
except IndexError as e:
log.error( log.error(
"YouTube: IndexError parsing Youtube API JSON response: %s" "YouTube: Error parsing Youtube API JSON response: %s"
% (str(e)) % (str(response))
) )
else: else:
log.error("YouTube: Error parsing Youtube API JSON response") irc.reply("No results found for: %s" % query)
else: return
log.error(
"YouTube: YouTube API HTTP %s: %s"
% (request.status_code, request.content.decode())
)
if title: if title:
use_bold = self.registryValue("useBold", channel) use_bold = self.registryValue("useBold", msg.channel)
if use_bold: if use_bold:
title = ircutils.bold(title) title = ircutils.bold(title)
irc.reply(title, prefixNick=False) irc.reply(title, prefixNick=False)

View File

@ -1,5 +0,0 @@
requests
pendulum
beautifulsoup4
fake_useragent
jinja2