591 lines
16 KiB
Python
591 lines
16 KiB
Python
###
|
|
# Copyright (c) 2021, Pratyush Desai
|
|
# All rights reserved.
|
|
#
|
|
#
|
|
###
|
|
|
|
# Other libs
|
|
|
|
import praw
|
|
import time
|
|
# For handling comments
|
|
from praw.models import MoreComments
|
|
# For sending messages to other channels/users
|
|
from supybot import ircmsgs
|
|
# For determing "now" compared to when posts are created
|
|
from datetime import datetime
|
|
# For tinyurls
|
|
import urllib
|
|
import requests
|
|
|
|
# Limnoria Libraries
|
|
|
|
from supybot import utils, plugins, ircutils, callbacks
|
|
from supybot.commands import *
|
|
try:
|
|
from supybot.i18n import PluginInternationalization
|
|
_ = PluginInternationalization('Redditt')
|
|
except ImportError:
|
|
# Placeholder that allows to run the plugin on a bot
|
|
# without the i18n module
|
|
def _(x): return x
|
|
|
|
|
|
|
|
|
|
class Reddit(callbacks.Plugin):
|
|
"""Interact with Reddit using the PRAW library"""
|
|
threaded = True
|
|
|
|
def __init__(self, irc):
|
|
self.__parent = super(Reddit, self)
|
|
self.__parent.__init__(irc)
|
|
# If we ever want to use a DB for this.
|
|
# self.db = {}
|
|
# self._loadDb()
|
|
# world.flushers.append(self._flushDb)
|
|
|
|
def getposts(self, irc, msg, args, opts, sub):
|
|
""" [--num <i>] [--sort <hot|new|controversial|gilded|top|rising>] [<subreddit>]
|
|
|
|
Gets [number] [sort] submissions (posts) based on flags provided.
|
|
"""
|
|
opts = dict(opts)
|
|
|
|
if sub:
|
|
subname = sub
|
|
else:
|
|
subname = 'TripSit'
|
|
subreddit = reddit.subreddit(subname)
|
|
|
|
if 'num' in opts:
|
|
num = opts['num']
|
|
else:
|
|
num = 10
|
|
|
|
sort = 'new'
|
|
if 'sort' in opts:
|
|
sort = opts['sort']
|
|
if sort == 'hot':
|
|
submissions = subreddit.hot(limit=num)
|
|
elif sort == 'controversial':
|
|
submissions = subreddit.controversial(limit=num)
|
|
elif sort == 'top':
|
|
submissions = subreddit.top(limit=num)
|
|
elif sort == 'gilded':
|
|
submissions = subreddit.gilded(limit=num)
|
|
elif sort == 'rising':
|
|
submissions = subreddit.rising(limit=num)
|
|
elif sort == 'new':
|
|
submissions = subreddit.new(limit=num)
|
|
else:
|
|
submissions = subreddit.new(limit=num)
|
|
|
|
irc.reply("Displaying {} {} submissions from r/Tripsit:".format(
|
|
num,
|
|
sort), prefixNick=False)
|
|
for submission in submissions:
|
|
# tiny_url = "http://tinyurl.com/api-create.php"
|
|
# url = tiny_url + "?" + urllib.parse.urlencode({"url": submission.url})
|
|
# res = requests.get(url)
|
|
# irc.reply("STATUS CODE:", res.status_code)
|
|
# irc.reply(" LONG URL:", submission.url)
|
|
# irc.reply(" SHORT URL:", res.text)
|
|
irc.reply("[{id}]\x0303 (S{score})\x0F (C{comments}) \x1F{author}\x0F: {title} {url}".format(
|
|
id=submission.id,
|
|
score=submission.score,
|
|
author=submission.author.name,
|
|
title=submission.title,
|
|
url=submission.url,
|
|
comments=submission.num_comments), prefixNick=False)
|
|
getposts = wrap(
|
|
getposts,
|
|
[
|
|
getopts(
|
|
{
|
|
"num": "int",
|
|
"sort": ("literal", ("hot", "new", "controversial", "gilded", "top", "rising"))
|
|
}
|
|
),
|
|
optional("something")
|
|
]
|
|
)
|
|
|
|
def modtools(self, irc, msg, args, opts, identifier):
|
|
"""--target <posts|comments> --do <remove|approve|lock|unlock> <id>
|
|
|
|
Provides a set of tools for moderating subreddits.
|
|
"""
|
|
opts = dict(opts)
|
|
if 'do' not in opts or 'target' not in opts:
|
|
irc.error(
|
|
"Please specify a target and an action using the appropriate format.")
|
|
return
|
|
if opts['do'] == "lock":
|
|
if opts['target'] == 'posts':
|
|
submissions = reddit.submission(id=identifier)
|
|
submissions.mod.lock()
|
|
elif opts['target'] == 'comments':
|
|
comments = reddit.comment(identifier)
|
|
comments.mod.lock()
|
|
elif opts['do'] == "unlock":
|
|
if opts['target'] == 'posts':
|
|
submissions = reddit.submission(id=identifier)
|
|
submissions.mod.unlock()
|
|
elif opts['target'] == 'comments':
|
|
comments = reddit.comment(identifier)
|
|
comments.mod.unlock()
|
|
if opts['do'] == "remove":
|
|
if opts['target'] == 'posts':
|
|
submissions = reddit.submission(id=identifier)
|
|
submissions.mod.remove()
|
|
elif opts['target'] == 'comments':
|
|
comments = reddit.comment(identifier)
|
|
comments.mod.remove()
|
|
elif opts['do'] == "approve":
|
|
if opts['target'] == 'posts':
|
|
submissions = reddit.submission(id=identifier)
|
|
submissions.mod.approve()
|
|
elif opts['target'] == 'comments':
|
|
comments = reddit.comment(identifier)
|
|
comments.mod.approve()
|
|
irc.replySuccess()
|
|
modtools = wrap(
|
|
modtools,
|
|
[
|
|
getopts(
|
|
{
|
|
"target": ("literal", ("posts", "comments")),
|
|
"do": ("literal", ("lock", "unlock", "remove", "approve"))
|
|
}
|
|
),
|
|
"something"
|
|
]
|
|
)
|
|
|
|
def comments(self, irc, msg, args, opts, submissionId):
|
|
""" [--num <i>] [--sort <confidence|new|controversial|old|q&a|top>] [<submissionId|submissionURL>]
|
|
|
|
Gets a list of comments from a submission (post), if a post ID/URL is provided
|
|
If no ID/URL is provided, it will get the [number] [sort] comments on /r/tripsit
|
|
"""
|
|
opts = dict(opts)
|
|
|
|
if submissionId:
|
|
if submissionId.find('reddit.com') == -1 and submissionId.find('r/') > 0:
|
|
sub_name = submissionId[3:]
|
|
subreddit = reddit.subreddit(sub_name)
|
|
|
|
# Determine "limit" of posts to get
|
|
if 'num' in opts:
|
|
num = opts['num']
|
|
else:
|
|
num = 10
|
|
|
|
comments = subreddit.comments(limit=num)
|
|
|
|
irc.reply("Displaying {} new comments from r/{}:".format(
|
|
num,
|
|
subreddit), prefixNick=False)
|
|
|
|
for comment in comments:
|
|
# Ignore "more" comments
|
|
if isinstance(comment, MoreComments):
|
|
continue
|
|
|
|
# Ignore AutoModerator comments
|
|
if comment.author == 'AutoModerator':
|
|
continue
|
|
|
|
irc.reply("\x0303 ({}) \x0F \x1F{}\x0F: {}".format(
|
|
comment.score, comment.author, comment.body), prefixNick=False)
|
|
irc.replySuccess()
|
|
return
|
|
if submissionId.find('reddit.com') > 0:
|
|
submission = reddit.submission(url=submissionId)
|
|
if len(submissionId) == 6:
|
|
submission = reddit.submission(id=submissionId)
|
|
|
|
# Determine "limit" of posts to get
|
|
if 'num' in opts:
|
|
submission.comment_limit = opts['num']
|
|
else:
|
|
submission.comment_limit = 10
|
|
|
|
# Determine sort
|
|
if 'sort' in opts:
|
|
submission.comment_sort = opts['sort']
|
|
else:
|
|
submission.comment_sort = 'new'
|
|
|
|
# Go through the Top Level Comments
|
|
irc.reply("Displaying {} {} comments for post: \x1F{}\x0F".format(
|
|
submission.comment_limit, submission.comment_sort, submission.title))
|
|
for TLC in submission.comments:
|
|
# Ignore "more" comments
|
|
if isinstance(TLC, MoreComments):
|
|
continue
|
|
|
|
# Ignore AutoModerator comments
|
|
if TLC.author == 'AutoModerator':
|
|
continue
|
|
|
|
# Reply with comment details. Format:
|
|
# (score) author: body
|
|
irc.reply("\x0303({})\x0F \x1F{}\x0F: {}".format(
|
|
TLC.score, TLC.author, TLC.body), prefixNick=False)
|
|
else:
|
|
subreddit = reddit.subreddit("Tripsit")
|
|
|
|
# Determine "limit" of posts to get
|
|
if 'num' in opts:
|
|
num = opts['num']
|
|
else:
|
|
num = 10
|
|
|
|
comments = subreddit.comments(limit=num)
|
|
|
|
irc.reply("Displaying {} new comments from r/Tripsit:".format(
|
|
num))
|
|
|
|
for comment in comments:
|
|
# Ignore "more" comments
|
|
if isinstance(comment, MoreComments):
|
|
continue
|
|
|
|
# Ignore AutoModerator comments
|
|
if comment.author == 'AutoModerator':
|
|
continue
|
|
|
|
irc.reply("\x0303 ({}) \x0F \x1F{}\x0F: {}".format(
|
|
comment.score, comment.author, comment.body), prefixNick=False)
|
|
# Success message so you know it didn't error out
|
|
irc.replySuccess()
|
|
comments = wrap(
|
|
comments,
|
|
[
|
|
getopts(
|
|
{
|
|
"num": "int",
|
|
"sort": ("literal", ("confidence", "new", "controversial", "old", "q&a", "top"))
|
|
}
|
|
),
|
|
optional("text")
|
|
]
|
|
)
|
|
|
|
def msg(self, irc, msg, args, opts, text):
|
|
""" --chan (#channel) text
|
|
|
|
More helpful doc string
|
|
"""
|
|
opts = dict(opts)
|
|
if len(opts) > 0:
|
|
irc.reply(text, to=opts['chan'])
|
|
else:
|
|
irc.reply(text)
|
|
|
|
# Success message so you know it finished
|
|
irc.replySuccess()
|
|
msg = wrap(
|
|
msg,
|
|
[
|
|
getopts(
|
|
{
|
|
"chan": "channel"
|
|
}
|
|
),
|
|
optional("text")
|
|
]
|
|
)
|
|
|
|
def rdie(self, irc, msg, args, opts, text):
|
|
"""Kills the process
|
|
|
|
or it should
|
|
"""
|
|
irc.reply("killing off function")
|
|
self.__parent.die()
|
|
|
|
# Success message so you know it finished
|
|
irc.replySuccess()
|
|
rdie = wrap(
|
|
rdie,
|
|
[
|
|
getopts(
|
|
{
|
|
"num": "int"
|
|
}
|
|
),
|
|
optional("text")
|
|
]
|
|
)
|
|
|
|
def watcher(self, irc, msg, args, opts, subreddit):
|
|
""" subreddit (optional, will default to TripSit)
|
|
|
|
More helpful doc string
|
|
"""
|
|
import time
|
|
started_watcher = int(round(time.time()))
|
|
enable_watcher = 1
|
|
irc.queueMsg(ircmsgs.privmsg(
|
|
"Moonbear", "Started watching at {}".format(started_watcher)))
|
|
|
|
if subreddit:
|
|
irc.reply("Starting watch on r/{}!".format(subreddit))
|
|
subreddit = reddit.subreddit(subreddit)
|
|
else:
|
|
irc.reply("Starting watch on r/TripSit!")
|
|
subreddit = reddit.subreddit('TripSit')
|
|
|
|
for submission in subreddit.stream.submissions():
|
|
post_created_utc = submission.created_utc
|
|
out = "{} posted {} @ {}".format(submission.author,
|
|
submission.title,
|
|
post_created_utc)
|
|
# irc.queueMsg(ircmsgs.privmsg("#tripsit-dev", out))
|
|
irc.queueMsg(ircmsgs.privmsg("Moonbear", out))
|
|
if post_created_utc > started_watcher:
|
|
irc.queueMsg(ircmsgs.privmsg("Moonbear", "I would post this"))
|
|
else:
|
|
irc.queueMsg(ircmsgs.privmsg(
|
|
"Moonbear", "I would NOT post this"))
|
|
if enable_watcher == 0:
|
|
break
|
|
# Success message so you know it finished
|
|
irc.replySuccess()
|
|
watcher = wrap(
|
|
watcher,
|
|
[
|
|
getopts(
|
|
{
|
|
"num": "int"
|
|
}
|
|
),
|
|
optional("text")
|
|
]
|
|
)
|
|
|
|
# This is a framework for a new funtion for easy copy-paste
|
|
def function_name(self, irc, msg, args, opts, text):
|
|
""" (string that appears when you "list module")
|
|
|
|
More helpful doc string
|
|
"""
|
|
|
|
# Success message so you know it finished
|
|
irc.replySuccess()
|
|
function_name = wrap(
|
|
function_name,
|
|
[
|
|
getopts(
|
|
{
|
|
"num": "int"
|
|
}
|
|
),
|
|
optional("text")
|
|
]
|
|
)
|
|
|
|
# Attributes so we don't need to grab them in the future
|
|
def commentAttributes():
|
|
"""Comment attributes, you can get these with "vars(submission)":
|
|
all_awardings
|
|
approved
|
|
approved_at_utc
|
|
approved_by
|
|
archived
|
|
associated_award
|
|
author
|
|
author_flair_background_color
|
|
author_flair_css_class
|
|
author_flair_richtext
|
|
author_flair_template_id
|
|
author_flair_text
|
|
author_flair_text_color
|
|
author_flair_type
|
|
author_fullname
|
|
author_patreon_flair
|
|
author_premium
|
|
awarders
|
|
banned_at_utc
|
|
banned_by
|
|
body
|
|
body_html
|
|
can_gild
|
|
can_mod_post
|
|
collapsed
|
|
collapsed_because_crowd_control
|
|
collapsed_reason
|
|
comment_type
|
|
controversiality
|
|
created
|
|
created_utc
|
|
depth
|
|
distinguished
|
|
downs
|
|
edited
|
|
gilded
|
|
gildings
|
|
id
|
|
ignore_reports
|
|
is_submitter
|
|
likes
|
|
link_id
|
|
locked
|
|
mod_note
|
|
mod_reason_by
|
|
mod_reason_title
|
|
mod_reports
|
|
name
|
|
no_follow
|
|
num_reports
|
|
parent_id
|
|
permalink
|
|
removal_reason
|
|
removed
|
|
report_reasons
|
|
saved
|
|
score
|
|
score_hidden
|
|
send_replies
|
|
spam
|
|
stickied
|
|
subreddit
|
|
subreddit_id
|
|
subreddit_name_prefixed
|
|
subreddit_type
|
|
top_awarded_type
|
|
total_awards_received
|
|
treatment_tags
|
|
ups
|
|
user_reports
|
|
_fetched
|
|
_reddit
|
|
_replies
|
|
_submission
|
|
"""
|
|
|
|
def submissionAttributes():
|
|
"""
|
|
allow_live_comments
|
|
all_awardings
|
|
approved
|
|
approved_at_utc
|
|
approved_by
|
|
archived
|
|
author
|
|
author_flair_background_color
|
|
author_flair_css_class
|
|
author_flair_richtext
|
|
author_flair_template_id
|
|
author_flair_text
|
|
author_flair_text_color
|
|
author_flair_type
|
|
author_fullname
|
|
author_patreon_flair
|
|
author_premium
|
|
awarders
|
|
banned_at_utc
|
|
banned_by
|
|
can_gild
|
|
can_mod_post
|
|
category
|
|
clicked
|
|
comment_limit
|
|
comment_sort
|
|
content_categories
|
|
contest_mode
|
|
created
|
|
created_utc
|
|
discussion_type
|
|
distinguished
|
|
domain
|
|
downs
|
|
edited
|
|
gilded
|
|
gildings
|
|
hidden
|
|
hide_score
|
|
id
|
|
ignore_reports
|
|
is_crosspostable
|
|
is_meta
|
|
is_original_content
|
|
is_reddit_media_domain
|
|
is_robot_indexable
|
|
is_self
|
|
is_video
|
|
likes
|
|
link_flair_background_color
|
|
link_flair_css_class
|
|
link_flair_richtext
|
|
link_flair_text
|
|
link_flair_text_color
|
|
link_flair_type
|
|
locked
|
|
media
|
|
media_embed
|
|
media_only
|
|
mod_note
|
|
mod_reason_by
|
|
mod_reason_title
|
|
mod_reports
|
|
name
|
|
no_follow
|
|
num_comments
|
|
num_crossposts
|
|
num_reports
|
|
over_18
|
|
parent_whitelist_status
|
|
permalink
|
|
pinned
|
|
pwls
|
|
quarantine
|
|
removal_reason
|
|
removed
|
|
removed_by
|
|
removed_by_category
|
|
report_reasons
|
|
saved
|
|
score
|
|
secure_media
|
|
secure_media_embed
|
|
selftext
|
|
selftext_html
|
|
send_replies
|
|
spam
|
|
spoiler
|
|
stickied
|
|
subreddit
|
|
subreddit_id
|
|
subreddit_name_prefixed
|
|
subreddit_subscribers
|
|
subreddit_type
|
|
suggested_sort
|
|
thumbnail
|
|
title
|
|
top_awarded_type
|
|
total_awards_received
|
|
treatment_tags
|
|
ups
|
|
upvote_ratio
|
|
url
|
|
user_reports
|
|
view_count
|
|
visited
|
|
whitelist_status
|
|
wls
|
|
_comments_by_id
|
|
_fetched
|
|
_reddit
|
|
"""
|
|
|
|
|
|
Class = Reddit
|
|
|
|
|
|
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
|