diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d692e7b --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +# Byte-compiled / optimized / DLL files / pip / IDE +__pycache__/ +*.py[cod] +*$py.class +src/ +.idea/ + +# Config +config.ini diff --git a/README.md b/README.md index bd114e6..bd822ea 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,17 @@ -# Pi Hole stats tweeter -I want to send a a daily tweet with the results of what my Pi-Hole blocked. Here is the code, run in Python3. +# Pi-Hole stats tweeter +Send a daily tweet with your Pi-Hole statistics! # How to use -Install following python dependencies with sudo pip install: - tweepy - datetime - json - urllib - -Download python file and replace it with your own account data and link to your own path/to/admin/api.php +1. Install Python 3 +2. `pip install -U - r requirements.txt` +3. Copy config.ini.example to config.ini and adjust it + 3.1. `api_path` = Path to your /admin/api.php of Pi-Hole + 3.2. Tokens: Create an application [here](https://apps.twitter.com/) +4. Run it! # Cronjob -This will tweet your stats at 23:59 everyday +This will tweet your stats at 23:59 everyday and redirects output to /dev/null: -59 23 * * * sudo python3 /home/pi/Desktop/twittertweeter.py >/dev/null 2>&1 - -# Twitter acces keys and tokens -On their own website it is quite clearly explained: https://dev.twitter.com/oauth/overview/application-owner-access-tokens - -# Reddit -https://www.reddit.com/r/pihole/comments/67umvj/need_help_with_doing_a_daily_pihole_tweet/ +``` +59 23 * * * python3 /path/to/pihole_tweeter.py >/dev/null 2>&1 +``` diff --git a/config.ini.example b/config.ini.example new file mode 100644 index 0000000..26d8c40 --- /dev/null +++ b/config.ini.example @@ -0,0 +1,6 @@ +[DEFAULT] +api_path = http://localhost/admin/api.php +consumer_key = CONSUMERKEY +consumer_secret = CONSUMERSECRET +access_token = ACCESS-TOKEN +access_token_secret = ACCESSTOKENSECRET diff --git a/pihole_tweeter.py b/pihole_tweeter.py new file mode 100644 index 0000000..6d235cf --- /dev/null +++ b/pihole_tweeter.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +import sys +from configparser import ConfigParser +from datetime import datetime + +import tweepy +from requests import get + +config = ConfigParser() +try: + config.read_file(open('config.ini')) +except FileNotFoundError: + print('config.ini not found.') + sys.exit(1) + +# API path +try: + api_path = config['DEFAULT']['api_path'] + consumer_key = config['DEFAULT']['consumer_key'] + consumer_secret = config['DEFAULT']['consumer_secret'] + access_token = config['DEFAULT']['access_token'] + access_token_secret = config['DEFAULT']['access_token_secret'] +except KeyError as exception: + print('Please check your config.ini.') + sys.exit(1) +if not (api_path, consumer_key, consumer_key, consumer_secret, access_token, access_token_secret): + print('2 Please check your config.ini.') + sys.exit(1) + + +def comma_value(num): + """Helper function for thousand separators""" + return "{:,}".format(int(num)).replace(',', '.') + + +def get_api(): + auth = tweepy.OAuthHandler(consumer_key, consumer_secret) + auth.set_access_token(access_token, access_token_secret) + return tweepy.API(auth) + + +def get_pihole_data(): + try: + res = get(api_path) + except Exception as exception: + print('Could not contact API: ' + str(exception)) + return + + if res.status_code != 200: + print('Could not get data from Pi-Hole API.') + return + + try: + data = res.json() + except: + print('Got no or invalid JSON.') + return + if not all(k in data for k in + ('ads_blocked_today', 'ads_percentage_today', 'dns_queries_today', 'domains_being_blocked')): + print('This is not Pi-Hole JSON...') + return + + return data + + +def construct_tweet(data): + today = datetime.today().strftime("%d.%m.%Y") + tweet = 'Pi-Hole-Statistik für den {date}:\n'.format(date=today) + tweet += 'Blockierte Werbung: ' + str(comma_value(data['ads_blocked_today'])) + tweet += ' (' + str(round(data['ads_percentage_today'], 2)).replace('.', ',') + ' %)\n' + tweet += 'DNS-Abfragen: ' + str(comma_value(data['dns_queries_today'])) + '\n' + tweet += 'Domains auf der Blacklist: ' + str(comma_value(data['domains_being_blocked'])) + return tweet + + +def main(): + # Twitter login + api = get_api() + try: + print('Logged in as @' + api.me().screen_name) + except tweepy.error.TweepError: + print('Error while logging in - check your credentials.') + return + + # Get Pi-Hole info from API + data = get_pihole_data() + if not data: + return + + # Tweet it! + tweet = construct_tweet(data) + try: + status = api.update_status(status=tweet) + except tweepy.error.TweepError: + print('Status could not be posted.') + return + print('Status posted! https://twitter.com/' + status.author.screen_name + '/status/' + status.id_str) + + +if __name__ == '__main__': + main() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..96fc922 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +requests +tweepy \ No newline at end of file diff --git a/twittertweeter-ads.py b/twittertweeter-ads.py deleted file mode 100644 index e8cddfb..0000000 --- a/twittertweeter-ads.py +++ /dev/null @@ -1,42 +0,0 @@ -#Send tweet when script is called - -import tweepy -import datetime -import json -import urllib -from urllib.request import urlopen - -# Retrieve data and load it into a dictionary -data = urlopen('path/to/admin/api.php').read() #bytes -body = data.decode('utf-8') -data = json.loads(body) - -# Create tweet, adjust %.2f for amount of decimals you want or %i for a whole number -template_tweet = "\nAds Blocked: %s\nAds Percentage Today: %.2f\nDNS Queries Today: %s\nDomains Being Blocked: %s" -data = template_tweet % (data['ads_blocked_today'], - float (data['ads_percentage_today']), - data['dns_queries_today'], - data['domains_being_blocked'] - ) - -def get_api(cfg): - auth = tweepy.OAuthHandler(cfg['consumer_key'], cfg['consumer_secret']) - auth.set_access_token(cfg['access_token'], cfg['access_token_secret']) - return tweepy.API(auth) - -def main(): - # Fill in the values noted in previous step here - cfg = { - "consumer_key" : "VALUE", - "consumer_secret" : "VALUE", - "access_token" : "VALUE", - "access_token_secret" : "VALUE" - } - - api = get_api(cfg) - tweet = datetime.datetime.today().strftime("%Y-%m-%d") + " Daily Pi-Hole report\n " + data - status = api.update_status(status=tweet) - # Yes, tweet is called 'status' rather confusing - -if __name__ == "__main__": - main()