Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic comment permalink handling #69

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ If video "watch" links contain a playlist ID, the plugin will show the
playlist info as well as the video info by default. To disable this, set
`playlist_watch` to `False`.

If video "watch" links contain a comment ID, the plugin will **only** show info
about the comment by default. If you also want video info posted in this
situation, set `comment_watch` to `True`.

For videos, by default, only the video length, uploader (channel name), view
count, and upload date are shown. The included items, and the order in which
they appear, depend on the `info_items` setting, which is a list of keywords.
Expand Down
75 changes: 72 additions & 3 deletions sopel_youtube/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,13 @@
r"((?:T)(?P<h>[0-9]+([,.][0-9]+)?H)?"
r"(?P<m>[0-9]+([,.][0-9]+)?M)?"
r"(?P<s>[0-9]+([,.][0-9]+)?S)?)?$")
video_regex = re.compile(r'(?:youtube\.com/(?:watch\S*v=|shorts/|live/)|youtu\.be/)([\w-]+)')
video_regex = re.compile(
r'''
(?:
(?:youtube\.com/(?:shorts/|live/)|youtu\.be/)(?P<video1>[\w-]+)|
youtube\.com/watch/?(?:\S*[?&]v=(?P<video2>[\w-]+)|\S*[?&]lc=(?P<comment>[\w_-]+))+
)
''', re.VERBOSE)
playlist_regex = re.compile(r'youtube\.com/(playlist|watch)\S*list=([\w-]+)')


Expand Down Expand Up @@ -97,6 +103,11 @@ class YoutubeSection(StaticSection):
Whether to show playlist info if the list ID is embedded in a video watch link.
"""

comment_watch = BooleanAttribute('comment_watch', default=False)
"""
Whether to also show video info when video ID is included in a comment link.
"""


def configure(config):
config.define_section('youtube', YoutubeSection, validate=False)
Expand All @@ -107,7 +118,10 @@ def configure(config):
"info_items", "Which attributes to show in response to video links"
)
config.youtube.configure_setting(
"playlist_watch", "Show playlist info if embedded in video links?"
"playlist_watch", "Show playlist info if included in a video link?"
)
config.youtube.configure_setting(
"comment_watch", "Show video info if included in a comment link?"
)


Expand Down Expand Up @@ -179,7 +193,62 @@ def video_search(bot, trigger):
def get_video_info(bot, trigger, match=None):
"""Get information about the linked YouTube video."""
match = match or trigger
_say_video_result(bot, trigger, match.group(1), include_link=False)
comment = match.group('comment')
video = match.group('video1') or match.group('video2')

if comment:
_say_comment_result(bot, trigger, comment)
if not bot.settings.youtube.comment_watch:
return

if video:
_say_video_result(bot, trigger, video, include_link=False)


def _say_comment_result(bot, trigger, id_):
for n in range(num_retries + 1):
try:
result = bot.memory['youtube_api_client'].comments().list(
id=id_,
part='id,snippet',
fields=
'items('
'snippet('
'authorDisplayName,likeCount,publishedAt,textDisplay'
')'
')',
textFormat='plainText',
).execute(http=httplib2.Http()).get('items')
except ConnectionError:
if n >= num_retries:
bot.say('Maximum retries exceeded fetching YouTube video {}, '
'please try again later.'.format(id_))
return
sleep(random() * 2**n)
continue
except googleapiclient.errors.HttpError as e:
bot.say(_get_http_error_message(e))
return
except Exception as e:
# Catch-all, because enumerating all the possible exceptions is a waste of code lines
bot.say('Temporary error talking to YouTube: %s' % e)
return
break
if not result:
return
result = result[0]

# Formatting
snippet = result['snippet']
author = snippet['authorDisplayName']
likes = snippet['likeCount']
published = _format_datetime(bot, trigger, snippet["publishedAt"])
text = snippet['textDisplay']

message = '[YouTube] {author}: {text}'.format(author=author, text=text)
end = ' | 👍 {likes} | {date}'.format(likes=likes, date=published)

bot.say(message, truncation='…', trailing=end)


def _say_video_result(bot, trigger, id_, include_link=True):
Expand Down