From d7f8bf83a0df45e96fab5f481f4686ffc16367b4 Mon Sep 17 00:00:00 2001 From: samwiseg0 Date: Fri, 31 Aug 2018 15:13:19 -0400 Subject: [PATCH] Major change in data structure that should resolve the double data issue --- tautulli.py | 157 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 101 insertions(+), 56 deletions(-) diff --git a/tautulli.py b/tautulli.py index 41a1bd7..d2cf67e 100644 --- a/tautulli.py +++ b/tautulli.py @@ -1,134 +1,179 @@ -# Do not edit this script. Edit configuration.py import os -import shutil import tarfile -import requests import urllib.request -import geoip2.database +import time from datetime import datetime, timezone +import geoip2.database from influxdb import InfluxDBClient +import requests import configuration -current_time = datetime.now(timezone.utc).astimezone().isoformat() +CURRENT_TIME = datetime.now(timezone.utc).astimezone().isoformat() -payload = {'apikey': configuration.tautulli_api_key, 'cmd': 'get_activity'} +PAYLOAD = {'apikey': configuration.tautulli_api_key, 'cmd': 'get_activity'} -activity = requests.get('{}/api/v2'.format(configuration.tautulli_url), params=payload).json()['response']['data'] +ACTIVITY = requests.get('{}/api/v2'.format(configuration.tautulli_url), + params=PAYLOAD).json()['response']['data'] -sessions = {d['session_id']: d for d in activity['sessions']} +SESSIONS = {d['session_id']: d for d in ACTIVITY['sessions']} + +TAR_DBFILE = '{}/GeoLite2-City.tar.gz'.format(os.path.dirname(os.path.realpath(__file__))) + +DBFILE = '{}/GeoLite2-City.mmdb'.format(os.path.dirname(os.path.realpath(__file__))) + +NOW = time.time() + +DB_AGE = NOW - (86400 * 35) + +#remove the running db file if it is older than 35 days +try: + t = os.stat(DBFILE) + c = t.st_ctime + if c < DB_AGE: + os.remove(DBFILE) +except FileNotFoundError: + pass -def GeoLite2db(ipaddress): - tar_dbfile = '{}/GeoLite2-City.tar.gz'.format(os.path.dirname(os.path.realpath(__file__))) +def geo_lookup(ipaddress): + """Lookup an IP using the local GeoLite2 DB""" + if not os.path.isfile(DBFILE): + urllib.request.urlretrieve( + 'http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz', + TAR_DBFILE) - dbfile = '{}/GeoLite2-City.mmdb'.format(os.path.dirname(os.path.realpath(__file__))) - - if not os.path.isfile(dbfile): - urllib.request.urlretrieve('http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz', tar_dbfile) - - tar = tarfile.open(tar_dbfile, "r:gz") + tar = tarfile.open(TAR_DBFILE, "r:gz") for files in tar.getmembers(): if 'GeoLite2-City.mmdb' in files.name: files.name = os.path.basename(files.name) tar.extract(files, '{}/'.format(os.path.dirname(os.path.realpath(__file__)))) - reader = geoip2.database.Reader(dbfile) - geodata = reader.city(ipaddress) + reader = geoip2.database.Reader(DBFILE) - return geodata + return reader.city(ipaddress) -influx_payload = [ +INFLUX_PAYLOAD = [ { "measurement": "Tautulli", "tags": { "type": "stream_count" }, - "time": current_time, + "time": CURRENT_TIME, "fields": { - "current_streams": int(activity['stream_count']), - "transcode_streams": int(activity['stream_count_transcode']), - "direct_play_streams": int(activity['stream_count_direct_play']), - "direct_streams": int(activity['stream_count_direct_stream']) + "current_streams": int(ACTIVITY['stream_count']), + "transcode_streams": int(ACTIVITY['stream_count_transcode']), + "direct_play_streams": int(ACTIVITY['stream_count_direct_play']), + "direct_streams": int(ACTIVITY['stream_count_direct_stream']) } } ] -for session in sessions.keys(): +for session in SESSIONS.keys(): try: - geodata = GeoLite2db(sessions[session]['ip_address_public']) + geodata = geo_lookup(SESSIONS[session]['ip_address_public']) except ValueError: if configuration.tautulli_failback_ip: - geodata = GeoLite2db(configuration.tautulli_failback_ip) + geodata = geo_lookup(configuration.tautulli_failback_ip) else: - geodata = GeoLite2db(requests.get('http://ip.42.pl/raw').text) + geodata = geo_lookup(requests.get('http://ip.42.pl/raw').text) latitude = geodata.location.latitude - # Get the latitude of each session. If we cant find it then... if not geodata.location.latitude: latitude = 37.234332396 else: latitude = geodata.location.latitude - # Get the longitude of each session. If we cant find it then... if not geodata.location.longitude: longitude = -115.80666344 else: longitude = geodata.location.longitude - decision = sessions[session]['transcode_decision'] + decision = SESSIONS[session]['transcode_decision'] if decision == 'copy': decision = 'direct stream' - video_decision = sessions[session]['stream_video_decision'] + video_decision = SESSIONS[session]['stream_video_decision'] if video_decision == 'copy': video_decision = 'direct stream' - quality = sessions[session]['stream_video_resolution'] + elif video_decision == '': + video_decision = 'Music' + + quality = SESSIONS[session]['stream_video_resolution'] + # If the video resolution is empty. Asssume it's an audio stream + # and use the container for music if not quality: - quality = sessions[session]['container'].upper() + quality = SESSIONS[session]['container'].upper() elif quality in ('SD', 'sd'): - quality = sessions[session]['stream_video_resolution'].upper() + quality = SESSIONS[session]['stream_video_resolution'].upper() elif quality in '4k': - quality = sessions[session]['stream_video_resolution'].upper() + quality = SESSIONS[session]['stream_video_resolution'].upper() else: - quality = '{}p'.format(sessions[session]['stream_video_resolution']) + quality = '{}p'.format(SESSIONS[session]['stream_video_resolution']) - influx_payload.append( + + # Translate player_state to integers so we can colorize the table + player_state = SESSIONS[session]['state'].lower() + + if player_state == 'playing': + player_state = 0 + + elif player_state == 'paused': + player_state = 1 + + elif player_state == 'buffering': + player_state = 3 + + + INFLUX_PAYLOAD.append( { "measurement": "Tautulli", "tags": { "type": "Session", - "region_code": geodata.subdivisions.most_specific.iso_code, - "latitude": latitude, - "longitude": longitude, - "location": '{} - {}'.format(geodata.subdivisions.most_specific.name, geodata.city.name), - "session_key": sessions[session]['session_key'] - }, - "time": current_time, - "fields": { - "name": sessions[session]['friendly_name'], - "title": sessions[session]['full_title'], + "session_id": SESSIONS[session]['session_id'], + "name": SESSIONS[session]['friendly_name'], + "title": SESSIONS[session]['full_title'], + "platform": SESSIONS[session]['platform'], + "product_version": SESSIONS[session]['product_version'], "quality": quality, "video_decision": video_decision.title(), "transcode_decision": decision.title(), - "platform": sessions[session]['platform'], - "product_version": sessions[session]['product_version'], - "quality_profile": sessions[session]['quality_profile'], - "progress_percent": sessions[session]['progress_percent'], + "media_type": SESSIONS[session]['media_type'].title(), + "audio_codec": SESSIONS[session]['audio_codec'].upper(), + "audio_profile": SESSIONS[session]['audio_profile'].upper(), + "stream_audio_codec": SESSIONS[session]['stream_audio_codec'].upper(), + "quality_profile": SESSIONS[session]['quality_profile'], + "progress_percent": SESSIONS[session]['progress_percent'], + "region_code": geodata.subdivisions.most_specific.iso_code, "location": geodata.city.name, + "full_location": '{} - {}'.format(geodata.subdivisions.most_specific.name, + geodata.city.name), + "latitude": latitude, + "longitude": longitude, + "player_state": player_state, + "device_type": SESSIONS[session]['platform'] + }, + "time": CURRENT_TIME, + "fields": { + "session_id": SESSIONS[session]['session_id'], + "session_key": SESSIONS[session]['session_key'] } } ) -influx = InfluxDBClient(configuration.influxdb_url, configuration.influxdb_port, configuration.influxdb_username, - configuration.influxdb_password, configuration.tautulli_influxdb_db_name) -influx.write_points(influx_payload) +INFLUX_SENDER = InfluxDBClient(configuration.influxdb_url, + configuration.influxdb_port, + configuration.influxdb_username, + configuration.influxdb_password, + configuration.tautulli_influxdb_db_name) + +INFLUX_SENDER.write_points(INFLUX_PAYLOAD)