Reddit/plugin.py

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: