From 56e8c3e066aa51a01468a381e90d330367f1c8ed Mon Sep 17 00:00:00 2001 From: lluni Date: Fri, 9 Dec 2022 00:04:01 +0100 Subject: [PATCH] Initial commit --- .env.example | 13 +++++++++ .gitignore | 5 ++++ README.md | 23 ++++++++++++++++ environment.yml | 10 +++++++ masto.py | 29 ++++++++++++++++++++ reddit.py | 23 ++++++++++++++++ script.py | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 174 insertions(+) create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 README.md create mode 100644 environment.yml create mode 100644 masto.py create mode 100644 reddit.py create mode 100644 script.py diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..5dbf49c --- /dev/null +++ b/.env.example @@ -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" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..77edef0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.vscode +.env +usercred.secret +clientcred.secret +post_toots.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000..0d9d34f --- /dev/null +++ b/README.md @@ -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. diff --git a/environment.yml b/environment.yml new file mode 100644 index 0000000..73cba50 --- /dev/null +++ b/environment.yml @@ -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 diff --git a/masto.py b/masto.py new file mode 100644 index 0000000..eef742c --- /dev/null +++ b/masto.py @@ -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") diff --git a/reddit.py b/reddit.py new file mode 100644 index 0000000..ab43ca2 --- /dev/null +++ b/reddit.py @@ -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()) \ No newline at end of file diff --git a/script.py b/script.py new file mode 100644 index 0000000..ba7d157 --- /dev/null +++ b/script.py @@ -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 + \ No newline at end of file