Rewrite #1
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
# Byte-compiled / optimized / DLL files / pip / IDE
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
src/
|
||||
.idea/
|
||||
|
||||
# Config
|
||||
config.ini
|
29
README.md
29
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. `pip3 install -U -r requirements.txt`
|
||||
3. Copy config.ini.example to config.ini and adjust it
|
||||
* `api_path` = Path to your /admin/api.php of Pi-Hole
|
||||
* 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
|
||||
```
|
||||
|
6
config.ini.example
Normal file
6
config.ini.example
Normal file
@ -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
|
102
pihole_tweeter.py
Normal file
102
pihole_tweeter.py
Normal file
@ -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()
|
2
requirements.txt
Normal file
2
requirements.txt
Normal file
@ -0,0 +1,2 @@
|
||||
requests
|
||||
tweepy
|
@ -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()
|
Reference in New Issue
Block a user