From c14b0852a726a6ee32e8c279db04880588caa0d1 Mon Sep 17 00:00:00 2001 From: oddluck Date: Thu, 21 May 2020 05:01:21 -0400 Subject: [PATCH] YouTube: remove dependencies, simplify, cleanup --- YouTube/README.md | 6 ++ YouTube/__init__.py | 2 +- YouTube/config.py | 6 +- YouTube/plugin.py | 203 ++++++++++++++++++--------------------- YouTube/requirements.txt | 5 - 5 files changed, 104 insertions(+), 118 deletions(-) delete mode 100644 YouTube/requirements.txt diff --git a/YouTube/README.md b/YouTube/README.md index a27415c..f7df2f7 100644 --- a/YouTube/README.md +++ b/YouTube/README.md @@ -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. `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` \ No newline at end of file diff --git a/YouTube/__init__.py b/YouTube/__init__.py index 2b0519b..cba98fa 100644 --- a/YouTube/__init__.py +++ b/YouTube/__init__.py @@ -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 # 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. __author__ = supybot.Author("oddluck", "oddluck", "oddluck@riseup.net") diff --git a/YouTube/config.py b/YouTube/config.py index e5c2aee..303749c 100644 --- a/YouTube/config.py +++ b/YouTube/config.py @@ -91,9 +91,9 @@ conf.registerChannelValue( YouTube, "template", registry.String( - "{{logo}} :: {{link}} :: {{title}} :: Duration: {{duration}} :: Views: {{views}} " - ":: Uploader: {{uploader}} :: Uploaded: {{published}} :: {{likes}} likes :: " - "{{dislikes}} dislikes :: {{favorites}} favorites :: {{comments}} comments", + "$logo :: $link :: $title :: Duration: $duration :: Views: $views :: Uploader:" + " $uploader :: Uploaded: $published :: $likes likes :: $dislikes dislikes ::" + " $favorites favorites :: $comments comments", _("""Template used for search result replies"""), ), ) diff --git a/YouTube/plugin.py b/YouTube/plugin.py index 60bfe5e..5cb9c27 100644 --- a/YouTube/plugin.py +++ b/YouTube/plugin.py @@ -35,11 +35,8 @@ import supybot.ircutils as ircutils import supybot.ircmsgs as ircmsgs import supybot.callbacks as callbacks import supybot.log as log -import requests -import pendulum -import json -from jinja2 import Template -from urllib.parse import urlencode +from string import Template +import datetime, json, re try: from supybot.i18n import PluginInternationalization @@ -56,10 +53,10 @@ class YouTube(callbacks.Plugin): threaded = True - def dosearch(self, query): + def dosearch(self, query, channel): apikey = self.registryValue("developerKey") - safe_search = self.registryValue("safeSearch", dynamic.channel) - sort_order = self.registryValue("sortOrder", dynamic.channel) + safe_search = self.registryValue("safeSearch", channel) + sort_order = self.registryValue("sortOrder", channel) video_id = None opts = { "q": query, @@ -71,19 +68,17 @@ class YouTube(callbacks.Plugin): "type": "video", } api_url = "https://www.googleapis.com/youtube/v3/search?{0}".format( - urlencode(opts) + utils.web.urlencode(opts) ) try: log.debug("YouTube: requesting %s" % (api_url)) - request = requests.get(api_url, timeout=10) - response = json.loads(request.content) + request = utils.web.getUrl(api_url).decode() + response = json.loads(request) video_id = response["items"][0]["id"]["videoId"] - except Exception: + except: log.error( - "YouTube: YouTube API HTTP %s: %s" - % (request.status_code, request.content.decode()) + "YouTube: Error retrieving data from API: %s" % request.content.decode() ) - pass return video_id 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 so that the duration can be parsed as usual. """ - duration = pendulum.parse(input) - return duration.total_seconds() + regex = re.compile( + r""" + (?P -?) P + (?:(?P \d+) Y)? + (?:(?P \d+) M)? + (?:(?P \d+) D)? + (?: T + (?:(?P \d+) H)? + (?:(?P\d+) M)? + (?:(?P\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): - date = pendulum.parse(date, strict=False) - 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) + def get_youtube_logo(self, channel): + use_bold = self.registryValue("useBold", channel) 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: - yt_logo = "{0}\x0F".format(self.registryValue("logo", dynamic.channel)) + yt_logo = "{0}\x0F".format(self.registryValue("logo", channel)) return yt_logo def yt(self, irc, msg, args, query): @@ -126,11 +134,12 @@ class YouTube(callbacks.Plugin): if not apikey: irc.reply("Error: You need to set an API key to use this plugin.") return - channel = msg.channel - yt_template = Template(self.registryValue("template", channel)) + template = self.registryValue("template", msg.channel) + template = template.replace("{{", "$").replace("}}", "") + template = Template(template) response = None title = None - video_id = self.dosearch(query) + video_id = self.dosearch(query, msg.channel) if video_id: log.debug("YouTube: got video id: %s" % video_id) opts = { @@ -139,91 +148,67 @@ class YouTube(callbacks.Plugin): "key": apikey, "id": video_id, } - opts = urlencode(opts) + opts = utils.web.urlencode(opts) api_url = "https://www.googleapis.com/youtube/v3/videos?%s" % (opts) log.debug("YouTube: requesting %s" % (api_url)) - request = requests.get(api_url, timeout=10) - ok = request.status_code == requests.codes.ok - if ok: - response = json.loads(request.content) - if response: - try: - if response["pageInfo"]["totalResults"] > 0: - items = response["items"] - video = items[0] - snippet = video["snippet"] - title = snippet["title"] - statistics = video["statistics"] - view_count = 0 - like_count = 0 - dislike_count = 0 - comment_count = 0 - favorite_count = 0 - if "viewCount" in statistics: - view_count = "{:,}".format(int(statistics["viewCount"])) - if "likeCount" in statistics: - like_count = "{:,}".format(int(statistics["likeCount"])) - if "dislikeCount" in statistics: - dislike_count = "{:,}".format( - int(statistics["dislikeCount"]) - ) - if "favoriteCount" in statistics: - favorite_count = "{:,}".format( - int(statistics["favoriteCount"]) - ) - if "commentCount" in statistics: - comment_count = "{:,}".format( - int(statistics["commentCount"]) - ) - channel_title = snippet["channelTitle"] - video_duration = video["contentDetails"]["duration"] - duration_seconds = self.get_total_seconds_from_duration( - video_duration - ) - if duration_seconds > 0: - duration = self.get_duration_from_seconds( - duration_seconds - ) - else: - duration = "LIVE" - published = snippet["publishedAt"] - published = self.get_published_date(published) - yt_logo = self.get_youtube_logo() - link = "https://youtu.be/%s" % (video_id) - compiled_template = yt_template.render( - { - "title": title, - "duration": duration, - "views": view_count, - "likes": like_count, - "dislikes": dislike_count, - "comments": comment_count, - "favorites": favorite_count, - "uploader": channel_title, - "link": link, - "published": published, - "logo": yt_logo, - } - ) - title = compiled_template - else: - log.debug( - "YouTube: video appears to be private; no results!" - ) - except IndexError as e: - log.error( - "YouTube: IndexError parsing Youtube API JSON response: %s" - % (str(e)) - ) + request = utils.web.getUrl(api_url).decode() + response = json.loads(request) + try: + if response["pageInfo"]["totalResults"] > 0: + items = response["items"] + video = items[0] + snippet = video["snippet"] + statistics = video["statistics"] + view_count = 0 + like_count = 0 + dislike_count = 0 + comment_count = 0 + favorite_count = 0 + if "viewCount" in statistics: + view_count = "{:,}".format(int(statistics["viewCount"])) + if "likeCount" in statistics: + like_count = "{:,}".format(int(statistics["likeCount"])) + if "dislikeCount" in statistics: + dislike_count = "{:,}".format(int(statistics["dislikeCount"])) + if "favoriteCount" in statistics: + favorite_count = "{:,}".format(int(statistics["favoriteCount"])) + if "commentCount" in statistics: + comment_count = "{:,}".format(int(statistics["commentCount"])) + channel_title = snippet["channelTitle"] + video_duration = video["contentDetails"]["duration"] + duration_seconds = self.get_total_seconds_from_duration( + video_duration + ) + if duration_seconds > 0: + duration = self.get_duration_from_seconds(duration_seconds) + else: + duration = "LIVE" + results = { + "title": snippet["title"], + "duration": duration, + "views": view_count, + "likes": like_count, + "dislikes": dislike_count, + "comments": comment_count, + "favorites": favorite_count, + "uploader": channel_title, + "link": "https://youtu.be/%s" % (video_id), + "published": snippet["publishedAt"].split("T")[0], + "logo": self.get_youtube_logo(msg.channel), + } + title = template.safe_substitute(results) else: - log.error("YouTube: Error parsing Youtube API JSON response") - else: + log.debug("YouTube: video appears to be private; no results!") + except: log.error( - "YouTube: YouTube API HTTP %s: %s" - % (request.status_code, request.content.decode()) + "YouTube: Error parsing Youtube API JSON response: %s" + % (str(response)) ) + else: + irc.reply("No results found for: %s" % query) + return if title: - use_bold = self.registryValue("useBold", channel) + use_bold = self.registryValue("useBold", msg.channel) if use_bold: title = ircutils.bold(title) irc.reply(title, prefixNick=False) diff --git a/YouTube/requirements.txt b/YouTube/requirements.txt deleted file mode 100644 index a679a3c..0000000 --- a/YouTube/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -requests -pendulum -beautifulsoup4 -fake_useragent -jinja2