Initial commit
This commit is contained in:
commit
56e8c3e066
7 changed files with 174 additions and 0 deletions
13
.env.example
Normal file
13
.env.example
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
REDDIT_USER_AGENT="Reddit Mastodon Crossposter"
|
||||||
|
REDDIT_AUTH_URL=""
|
||||||
|
REDDIT_AUTH_TOKEN=""
|
||||||
|
REDDIT_REFRESH_TOKEN=""
|
||||||
|
REDDIT_CLIENT_ID=""
|
||||||
|
REDDIT_CLIENT_SECRET=""
|
||||||
|
MASTODON_URL=""
|
||||||
|
MASTODON_EMAIL=""
|
||||||
|
MASTODON_PASSWORD=""
|
||||||
|
MASTODON_USER_ID=""
|
||||||
|
MASTODON_APP_NAME=""
|
||||||
|
MASTODON_USER_SECRET="usercred.secret"
|
||||||
|
MASTODON_CLIENT_SECRET="clientcred.secret"
|
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
.vscode
|
||||||
|
.env
|
||||||
|
usercred.secret
|
||||||
|
clientcred.secret
|
||||||
|
post_toots.sh
|
23
README.md
Normal file
23
README.md
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# Reddit Mastodon Crossposter
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
1. Install conda env with `conda env create -f environment.yml`.
|
||||||
|
|
||||||
|
2. Initialize PRAW with e.g. `reddit.py` (please refer to the [PRAW docs](https://praw.readthedocs.io)).
|
||||||
|
|
||||||
|
3. Initialize Mastodon.py with e.g. `masto.py` (please refer to the [Mastodon.py docs](https://mastodonpy.readthedocs.io)).
|
||||||
|
|
||||||
|
4. Set all `.env` variables if there are any remaining.
|
||||||
|
|
||||||
|
5. Create an `post_toots.sh` and make it executable:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
conda activate reddit
|
||||||
|
python "/absolute/path/to/script.py"
|
||||||
|
conda deactivate
|
||||||
|
```
|
||||||
|
|
||||||
|
6. Open the a (user) cronjob editor with `crontab -e` and add the line `0 * * * * /absolute/path/to/post_toots.sh > /dev/null 2>&1`. This cronjob runs hourly and the command outputs are not mailed to the user. Alternatively, `2>&1` can be ommited for debugging purposes if the error outputs should be mailed to the user.
|
10
environment.yml
Normal file
10
environment.yml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
name: reddit
|
||||||
|
channels:
|
||||||
|
- conda-forge
|
||||||
|
- defaults
|
||||||
|
dependencies:
|
||||||
|
- praw
|
||||||
|
- pip:
|
||||||
|
- mastodon-py==1.5.2
|
||||||
|
- python-dotenv==0.21.0
|
||||||
|
- wget==3.2
|
29
masto.py
Normal file
29
masto.py
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
"""Initialize Mastodon.py, login the account and register an application"""
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from mastodon import Mastodon
|
||||||
|
from os import getenv
|
||||||
|
|
||||||
|
# load .env
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
# register application
|
||||||
|
Mastodon.create_app(
|
||||||
|
getenv("MASTODON_APP_NAME"),
|
||||||
|
api_base_url = str(getenv("MASTODON_URL")),
|
||||||
|
to_file = getenv("MASTODON_CLIENT_SECRET")
|
||||||
|
)
|
||||||
|
|
||||||
|
# login
|
||||||
|
mastodon = Mastodon(
|
||||||
|
client_id = getenv("MASTODON_CLIENT_SECRET"),
|
||||||
|
api_base_url = getenv("MASTODON_URL")
|
||||||
|
)
|
||||||
|
mastodon.log_in(
|
||||||
|
getenv("MASTODON_USERNAME"),
|
||||||
|
getenv("MASTODON_PASSWORD"),
|
||||||
|
to_file = getenv("MASTODON_USER_SECRET")
|
||||||
|
)
|
||||||
|
|
||||||
|
# test toot
|
||||||
|
mastodon.toot("Hello World")
|
23
reddit.py
Normal file
23
reddit.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
"""Initialize PRAW"""
|
||||||
|
|
||||||
|
import praw
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from os import getenv
|
||||||
|
|
||||||
|
# load .env
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
# initialize reddit
|
||||||
|
reddit = praw.Reddit(
|
||||||
|
client_id = getenv("REDDIT_CLIENT_ID"),
|
||||||
|
client_secret = getenv("REDDIT_CLIENT_SECRET"),
|
||||||
|
redirect_uri = "http://localhost:8080", # does not matter what is here
|
||||||
|
user_agent = getenv("REDDIT_USER_AGENT")
|
||||||
|
)
|
||||||
|
|
||||||
|
# get auth URL
|
||||||
|
# print(reddit.auth.url(scopes=["identity", "read"], state="...", duration="permanent"))
|
||||||
|
|
||||||
|
# get refresh token
|
||||||
|
# print(reddit.auth.authorize(getenv("REDDIT_AUTH_TOKEN")))
|
||||||
|
# print(reddit.user.me())
|
71
script.py
Normal file
71
script.py
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
"""Main script to toot a new post"""
|
||||||
|
|
||||||
|
import praw, wget
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from mastodon import Mastodon
|
||||||
|
from os import getenv, remove
|
||||||
|
from os.path import getsize
|
||||||
|
|
||||||
|
# load .env
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
# initialize reddit
|
||||||
|
reddit = praw.Reddit(
|
||||||
|
client_id = getenv("REDDIT_CLIENT_ID"),
|
||||||
|
client_secret = getenv("REDDIT_CLIENT_SECRET"),
|
||||||
|
redirect_uri = "http://localhost:8080", # does not matter what is here
|
||||||
|
user_agent = getenv("REDDIT_USER_AGENT")
|
||||||
|
)
|
||||||
|
|
||||||
|
# initialize mastodon
|
||||||
|
mastodon = Mastodon(
|
||||||
|
access_token = getenv("MASTODON_USER_SECRET"),
|
||||||
|
api_base_url = getenv("MASTODON_URL")
|
||||||
|
)
|
||||||
|
|
||||||
|
# get recent posts to check for duplicates
|
||||||
|
last_posts = mastodon.account_statuses(getenv("MASTODON_USER_ID"), limit=15)
|
||||||
|
|
||||||
|
for submission in reddit.subreddit("ich_iel").top(time_filter="day", limit=10):
|
||||||
|
# skip post if it is a stickied post
|
||||||
|
if (submission.stickied):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# check if the post has been posted before
|
||||||
|
already_posted = False
|
||||||
|
for posted_submission in last_posts:
|
||||||
|
if submission.permalink in posted_submission["content"]:
|
||||||
|
already_posted = True
|
||||||
|
break
|
||||||
|
if already_posted:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# check if text only
|
||||||
|
if submission.is_self:
|
||||||
|
status_text = submission.title + "\n\ngeposted von u/" + submission.author.name + "\n" + submission.permalink + "\n\n" + submission.selftext
|
||||||
|
mastodon.status_post(status_text, visibility="unlisted")
|
||||||
|
# check if reddit video
|
||||||
|
elif "v.redd.it" in submission.url:
|
||||||
|
url = submission.media["reddit_video"]["fallback_url"]
|
||||||
|
url = url.split("?")[0]
|
||||||
|
filename = wget.download(url)
|
||||||
|
print()
|
||||||
|
|
||||||
|
# check if video file is small enough for the server (10MB)
|
||||||
|
if getsize(filename) < 10*1000000:
|
||||||
|
media = mastodon.media_post(filename)
|
||||||
|
status_text = submission.title + "\n\ngeposted von u/" + submission.author.name + "\nhttps://reddit.com" + submission.permalink
|
||||||
|
mastodon.status_post(status_text, media_ids=media["id"], visibility="unlisted")
|
||||||
|
else:
|
||||||
|
status_text = submission.title + "\n\nGeposteter Videolink: " + url + "\n\ngeposted von u/" + submission.author.name + "\n" + submission.permalink + "\n\n" + submission.selftext
|
||||||
|
mastodon.status_post(status_text, visibility="unlisted")
|
||||||
|
remove(filename)
|
||||||
|
else:
|
||||||
|
filename = wget.download(submission.url)
|
||||||
|
print()
|
||||||
|
media = mastodon.media_post(filename)
|
||||||
|
status_text = submission.title + "\n\ngeposted von u/" + submission.author.name + "\nhttps://reddit.com" + submission.permalink
|
||||||
|
mastodon.status_post(status_text, media_ids=media["id"], visibility="unlisted")
|
||||||
|
remove(filename)
|
||||||
|
break
|
||||||
|
|
Loading…
Reference in a new issue