Merge pull request #9 from vinyll/master

Install doc and reformatting
master 1.7
Ayush Sharma 2019-12-12 14:34:06 +05:30 committed by GitHub
commit ce45f1b7b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 71 additions and 99 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
/venv/
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]

View File

@ -13,7 +13,7 @@ Getting Tweet-Toot working is pretty easy. Before you can install it, you're goi
Once you have the above, just follow these steps:
1. Clone this repository.
2. Install the Python3 libraries `requests` and `beautifulsoup` mentioned in the `requirements.txt` file.
2. Install the Python3 libraries: `python3 -m venv venv`, then `source venv/bin/activate` and install dependencies `pip install -r requirements.txt`.
3. In `config.json`, update the following:
- `tweets.source_account_url`: The source Twitter account.
@ -30,6 +30,8 @@ For example:
## How do I run it?
Once it's all setup, just run the main file like this:
Activate the virtualenv you created on install (if it's not activated yet): `source venv/bin/activate` and run the script:
`python3 run.py`
If all goes well, you'll see something like this:
@ -70,4 +72,4 @@ The container has support for sending logs to Papertrail. Just add your authenti
- Mastodon instance admins are people too. Don't toot-blast your instance and make life harder for them.
- When configuring your bot, ensure you clearly display an account where you can be reached in case of issues.
Have fun :)
Have fun :)

View File

@ -11,32 +11,24 @@ def _config(key):
key {string} -- Name of the key in the config.json file.
"""
my_file = Path('config.json')
my_file = Path("config.json")
if not my_file.is_file():
print('--- Main config.json file not found. Exiting.')
print("--- Main config.json file not found. Exiting.")
sys.exit()
config_file = open('config.json')
config_file = open("config.json")
config = config_file.read()
if not config:
print('--- config.json invalid. Exiting.')
print("--- config.json invalid. Exiting.")
sys.exit()
config = json.loads(config)
if config.get(key):
return config.get(key)
else:
print('--- config.json invalid. Exiting.')
print("--- config.json invalid. Exiting.")
sys.exit()
@ -46,8 +38,7 @@ def _info(message):
Arguments:
message {string} -- Log message.
"""
print(' _info > ' + message)
print(f" _info > {message}")
def _error(message):
@ -56,5 +47,4 @@ def _error(message):
Arguments:
message {string} -- Log message.
"""
print(' _error > ' + message)
print(f" _error > {message}")

17
run.py
View File

@ -4,7 +4,7 @@ import social
import sys
if __name__ == '__main__':
if __name__ == "__main__":
""" It all starts here...
@ -15,20 +15,13 @@ if __name__ == '__main__':
tweets = social.getTweets()
if not tweets:
helpers._error(
'__main__ => No tweets fetched.')
helpers._error("__main__ => No tweets fetched.")
sys.exit()
helpers._info('__main__ => ' + str(len(tweets)) + ' tweets fetched.')
helpers._info(f"__main__ => {len(tweets)} tweets fetched.")
for tweet in tweets:
if social.tootTheTweet(tweet):
helpers._info('__main__ => Tooted "' + tweet['text'] + '"')
helpers._info(
'__main__ => Tooting less is tooting more. Sleeping...')
helpers._info(f'__main__ => Tooted "{tweet["text"]}"')
helpers._info("__main__ => Tooting less is tooting more. Sleeping...")
sys.exit()

121
social.py
View File

@ -4,6 +4,7 @@ from bs4 import BeautifulSoup
from pathlib import Path
import base64
def getTweets():
""" Get list of tweets, with tweet ID and content, from configured Twitter account URL.
@ -13,50 +14,38 @@ def getTweets():
"""
all_tweets = []
url = helpers._config('tweets.source_account_url')
url = helpers._config("tweets.source_account_url")
if not url:
helpers._error('getTweets() => The source Twitter account URL (' + url + ') was incorrect. Could not retrieve tweets.')
helpers._error(
f"getTweets() => The source Twitter account URL ({url}) was incorrect. Could not retrieve tweets.")
return False
headers = {}
headers['accept-language'] = 'en-US,en;q=0.9'
headers['dnt'] = '1'
headers['user-agent'] = helpers._config('gen.APP_NAME')
headers["accept-language"] = "en-US,en;q=0.9"
headers["dnt"] = "1"
headers["user-agent"] = helpers._config("gen.APP_NAME")
data = requests.get(url)
html = BeautifulSoup(data.text, 'html.parser')
timeline = html.select('#timeline li.stream-item')
html = BeautifulSoup(data.text, "html.parser")
timeline = html.select("#timeline li.stream-item")
if timeline is None:
helpers._error('getTweets() => Could not retrieve tweets from the page. Please make sure the source Twitter account URL (' + url + ') is correct.')
helpers._error(
f"getTweets() => Could not retrieve tweets from the page. Please make sure the source Twitter account URL ({url}) is correct."
)
return False
helpers._info('getTweets() => Fetched tweets for ' + url + '.')
helpers._info(f"getTweets() => Fetched tweets for {url}.")
for tweet in timeline:
tweet_id = tweet['data-item-id']
tweet_id = tweet["data-item-id"]
try:
tweet_text = tweet.select('p.tweet-text')[0].get_text()
tweet_text = tweet.select("p.tweet-text")[0].get_text()
except:
helpers._info('getTweets() => No tweet text found. Moving on...')
helpers._info("getTweets() => No tweet text found. Moving on...")
continue
all_tweets.append({"id": tweet_id, "text": tweet_text})
return all_tweets if len(all_tweets) > 0 else None
@ -71,62 +60,58 @@ def tootTheTweet(tweet):
tweet {dictionary} -- Dictionary containing the "id" and "text" of a single tweet.
"""
host_instance = helpers._config('toots.host_instance')
token = helpers._config('toots.app_secure_token')
tweet_id = tweet['id']
host_instance = helpers._config("toots.host_instance")
token = helpers._config("toots.app_secure_token")
tweet_id = tweet["id"]
if not host_instance:
helpers._error('tootTheTweet() => Your host Mastodon instance URL (' + host_instance + ') was incorrect.')
helpers._error(
f"tootTheTweet() => Your host Mastodon instance URL ({host_instance}) was incorrect."
)
return False
if not token:
helpers._error('tootTheTweet() => Your Mastodon access token was incorrect.')
return False
headers = {}
headers['Authorization'] = 'Bearer ' + token
headers['Idempotency-Key'] = tweet_id
data = {}
data['status'] = tweet['text']
data['visibility'] = 'public'
tweet_check_file_path = helpers._config('toots.cache_path') + tweet['id']
tweet_check_file = Path(tweet_check_file_path)
if tweet_check_file.is_file():
helpers._info('tootTheTweet() => Tweet ' + tweet_id + ' was already posted. Reposting...')
helpers._error("tootTheTweet() => Your Mastodon access token was incorrect.")
return False
else:
headers = {}
headers["Authorization"] = f"Bearer {token}"
headers["Idempotency-Key"] = tweet_id
tweet['text'].encode('utf-8')
tweet_check = open(tweet_check_file_path, mode='w')
tweet_check.write(tweet['text'])
data = {}
data["status"] = tweet["text"]
data["visibility"] = "public"
tweet_check_file_path = helpers._config("toots.cache_path") + tweet["id"]
tweet_check_file = Path(tweet_check_file_path)
if tweet_check_file.is_file():
helpers._info(
f"tootTheTweet() => Tweet {tweet_id} was already posted. Reposting..."
)
return False
else:
tweet["text"].encode("utf-8")
tweet_check = open(tweet_check_file_path, mode="w")
tweet_check.write(tweet["text"])
tweet_check.close()
helpers._info('tootTheTweet() => New tweet ' + tweet_id + ' => "' + tweet['text'] + '".')
helpers._info(
f'tootTheTweet() => New tweet {tweet_id} => "{tweet["text"]}".'
)
response = requests.post(
url=host_instance + '/api/v1/statuses', data=data, headers=headers)
url=f"{host_instance}/api/v1/statuses", data=data, headers=headers
)
if response.status_code == 200:
helpers._info('tootTheTweet() => OK. Posted tweet ' + tweet_id + 'to Mastodon.')
helpers._info('tootTheTweet() => Response: ' + response.text)
helpers._info(f"tootTheTweet() => OK. Posted tweet {tweet_id} to Mastodon.")
helpers._info(f"tootTheTweet() => Response: {response.text}")
return True
else:
helpers._info('tootTheTweet() => FAIL. Could not post tweet ' + tweet_id + 'to Mastodon.')
helpers._info('tootTheTweet() => Response: ' + response.text)
helpers._info(
f"tootTheTweet() => FAIL. Could not post tweet {tweet_id} to Mastodon."
)
helpers._info(f"tootTheTweet() => Response: {response.text}")
return False