Add back reddit inbox listening mode; now configurable using the 'mode' config parameter.
Add support for notifying reddit users of generation in 'immediately' mode.
This commit is contained in:
parent
abb36769fe
commit
809ffd05ec
|
@ -11,7 +11,7 @@ pip3 install --upgrade https://git.caspervk.net/caspervk/dailyreleases/archive/m
|
||||||
**It requires Python 3.6 or later.**
|
**It requires Python 3.6 or later.**
|
||||||
|
|
||||||
### Usage
|
### Usage
|
||||||
The program can be started by running `dailyreleases` or `python3 -m dailyreleases` depending on system configuration.
|
The bot can be started by running `dailyreleases` or `python3 -m dailyreleases` depending on system configuration.
|
||||||
|
|
||||||
### Configuration
|
### Configuration
|
||||||
The default configuration file will be copied to `~/.dailyreleases/config.ini` on the first run. All fields under the
|
The default configuration file will be copied to `~/.dailyreleases/config.ini` on the first run. All fields under the
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
[main]
|
[main]
|
||||||
# true : Listen for reddit PMs; on receipt, generate and submit post to own subreddit. Reply with link to post.
|
|
||||||
# false : Immediately generate and print post to log and console. Nothing is posted to reddit.
|
# mode =
|
||||||
production = false
|
# immediately : Immediately generate and submit post to own subreddit. PM reddit notify_users with link to post.
|
||||||
|
# reply : Listen for reddit PMs; on receipt, generate and submit post to own subreddit. Reply with link to post.
|
||||||
|
# test : Generate and print to log and console. Nothing is posted to reddit.
|
||||||
|
mode = test
|
||||||
|
|
||||||
|
|
||||||
[logging]
|
[logging]
|
||||||
|
@ -19,10 +22,15 @@ user_agent = <platform>:<app ID>:<version string> (by /u/<reddit username>)
|
||||||
username = xxxxxxxxxxxxx
|
username = xxxxxxxxxxxxx
|
||||||
password = xxxxxxx
|
password = xxxxxxx
|
||||||
|
|
||||||
# List of users who are allowed to PM the bot.
|
# List of users who are authorized to start the generation by PM'ing the bot. Only applies to 'reply' mode.
|
||||||
authorized_users = spez,Deimorz,kn0thing
|
authorized_users = spez,Deimorz,kn0thing
|
||||||
|
|
||||||
# Reddit perceives PMs with many links as spam, so the bot posts the code for the generated post in its own subreddit.
|
# List of users who should receive a PM on generation. Only applies to 'immediately' mode, since the sender will receive
|
||||||
|
# the PM in 'reply' mode.
|
||||||
|
notify_users = chooter,GallowBoob
|
||||||
|
|
||||||
|
# Reddit perceives PMs with many links as spam, so the bot posts the code for the generated post in its own subreddit
|
||||||
|
# instead of sending it directly in the PM.
|
||||||
bot_subreddit = dailyreleases
|
bot_subreddit = dailyreleases
|
||||||
|
|
||||||
# It also needs to know of the subreddit where the daily releases threads are posted so it can link to the previous one.
|
# It also needs to know of the subreddit where the daily releases threads are posted so it can link to the previous one.
|
||||||
|
@ -42,5 +50,5 @@ key = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
|
||||||
[web]
|
[web]
|
||||||
# Number of seconds to cache web requests (google, steam etc.). May help reduce the number of requests if the same game
|
# Number of seconds to cache web requests (google, steam etc.). May help reduce the number of requests if the same game
|
||||||
# has multiple scene releases on the same day.
|
# has multiple releases on the same day.
|
||||||
cache_time = 600
|
cache_time = 600
|
|
@ -1,3 +1,4 @@
|
||||||
|
import inspect
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
|
@ -7,6 +8,7 @@ import time
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
import prawcore
|
||||||
import requests_cache
|
import requests_cache
|
||||||
|
|
||||||
from dailyreleases import config, __version__, util
|
from dailyreleases import config, __version__, util
|
||||||
|
@ -41,12 +43,38 @@ class DailyReleasesBot(object):
|
||||||
self.reddit = Reddit(self.config)
|
self.reddit = Reddit(self.config)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
# If not production, generate now (without posting to reddit) and then exit
|
mode = self.config["main"]["mode"]
|
||||||
if not self.config["main"].getboolean("production"):
|
|
||||||
self.generate()
|
|
||||||
return
|
|
||||||
|
|
||||||
self.generate(do_post=True)
|
if mode == "test":
|
||||||
|
self.generate(post=False)
|
||||||
|
|
||||||
|
if mode == "immediately":
|
||||||
|
self.generate(post=True, pm_recipients=self.config["reddit"]["notify_users"].split(","))
|
||||||
|
|
||||||
|
if mode == "reply":
|
||||||
|
self.listen_inbox()
|
||||||
|
|
||||||
|
def listen_inbox(self):
|
||||||
|
logger.info("Listening on reddit inbox stream")
|
||||||
|
authorized_users = self.config["reddit"]["authorized_users"].split(",")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
for message in self.reddit.praw.inbox.stream():
|
||||||
|
if message.author in authorized_users:
|
||||||
|
self.generate(post=True, pm_recipients=(message.author.name,))
|
||||||
|
else:
|
||||||
|
logger.info("Discarding PM from %s: not authorized user", message.author)
|
||||||
|
|
||||||
|
message.mark_read() # mark message read last so we can retry after potential fatal errors
|
||||||
|
|
||||||
|
except prawcore.PrawcoreException as e:
|
||||||
|
logger.warning("PrawcoreException: %s", e)
|
||||||
|
logger.info("Restarting inbox listener..")
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("Exiting (KeyboardInterrupt)")
|
||||||
|
break
|
||||||
|
|
||||||
def find_store_links(self, game_name) -> dict:
|
def find_store_links(self, game_name) -> dict:
|
||||||
links = {}
|
links = {}
|
||||||
|
@ -349,7 +377,7 @@ class DailyReleasesBot(object):
|
||||||
logger.debug("Generated post:\n%s", post_str)
|
logger.debug("Generated post:\n%s", post_str)
|
||||||
return post_str
|
return post_str
|
||||||
|
|
||||||
def generate(self, do_post=False):
|
def generate(self, post=False, pm_recipients=None):
|
||||||
logger.info("-------------------------------------------------------------------------------------------------")
|
logger.info("-------------------------------------------------------------------------------------------------")
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
|
|
||||||
|
@ -358,26 +386,41 @@ class DailyReleasesBot(object):
|
||||||
releases = self.predb.get_releases()
|
releases = self.predb.get_releases()
|
||||||
parsed_releases, failed_dirnames = self.parse_releases(releases, already_posted)
|
parsed_releases, failed_dirnames = self.parse_releases(releases, already_posted)
|
||||||
|
|
||||||
post = self.generate_post(parsed_releases)
|
|
||||||
source = textwrap.indent(post, " ")
|
|
||||||
|
|
||||||
# The date of the post changes at midday instead of midnight to allow calling script after 00:00
|
# The date of the post changes at midday instead of midnight to allow calling script after 00:00
|
||||||
title = "Daily Releases ({})".format((datetime.today() - timedelta(hours=12)).strftime("%B %-d, %Y"))
|
title = "Daily Releases ({})".format((datetime.today() - timedelta(hours=12)).strftime("%B %-d, %Y"))
|
||||||
|
|
||||||
if do_post:
|
generated_post = self.generate_post(parsed_releases)
|
||||||
# Post to bot's subreddit
|
generated_post_src = textwrap.indent(generated_post, " ")
|
||||||
source_post = self.reddit.submit_post(f"{title} - Source", source, self.config["reddit"]["bot_subreddit"])
|
|
||||||
preview_post = self.reddit.submit_post(title, post, self.config["reddit"]["bot_subreddit"])
|
if post:
|
||||||
|
# Post to bot's own subreddit
|
||||||
|
bot_subreddit = self.config["reddit"]["bot_subreddit"]
|
||||||
|
reddit_src_post = self.reddit.submit_post(f"{title} - Source", generated_post_src, bot_subreddit)
|
||||||
|
reddit_post = self.reddit.submit_post(title, generated_post, bot_subreddit)
|
||||||
|
|
||||||
# Manually approve posts since reddit seem to think posts with many links are spam
|
# Manually approve posts since reddit seem to think posts with many links are spam
|
||||||
source_post.mod.approve()
|
reddit_src_post.mod.approve()
|
||||||
preview_post.mod.approve()
|
reddit_post.mod.approve()
|
||||||
|
|
||||||
self.save_already_posted(already_posted)
|
self.save_already_posted(already_posted)
|
||||||
|
|
||||||
|
if pm_recipients is not None:
|
||||||
|
msg = inspect.cleandoc(
|
||||||
|
f"""
|
||||||
|
[Preview]({reddit_post.url})
|
||||||
|
[Source]({reddit_src_post.url})
|
||||||
|
Failed: {", ".join(failed_dirnames)}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
for recipient in pm_recipients:
|
||||||
|
self.reddit.send_pm(recipient, title, msg)
|
||||||
|
|
||||||
logger.info("Execution took %s seconds", int(time.time() - start_time))
|
logger.info("Execution took %s seconds", int(time.time() - start_time))
|
||||||
logger.info("-------------------------------------------------------------------------------------------------")
|
logger.info("-------------------------------------------------------------------------------------------------")
|
||||||
|
|
||||||
|
# Clean requests cache after each successful generation so it doesn't grow indefinitely
|
||||||
|
self.cache.remove_expired_responses()
|
||||||
|
|
||||||
def load_already_posted(self):
|
def load_already_posted(self):
|
||||||
try:
|
try:
|
||||||
with config.DATA_DIR.joinpath("already_posted").open() as file:
|
with config.DATA_DIR.joinpath("already_posted").open() as file:
|
||||||
|
|
Reference in a new issue