Migrated tautulli.py and allowed for multiple servers
This commit is contained in:
parent
32b965edf8
commit
7638cd937e
8 changed files with 439 additions and 206 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -12,4 +12,4 @@ GeoLite2-City.mmdb
|
|||
GeoLite2-City.tar.gz
|
||||
.idea/
|
||||
.idea/*
|
||||
Varken/varken.ini
|
||||
varken.ini
|
||||
|
|
|
@ -1,179 +0,0 @@
|
|||
import os
|
||||
import tarfile
|
||||
import urllib.request
|
||||
import time
|
||||
from datetime import datetime, timezone
|
||||
import geoip2.database
|
||||
from influxdb import InfluxDBClient
|
||||
import requests
|
||||
from Varken import configuration
|
||||
|
||||
CURRENT_TIME = datetime.now(timezone.utc).astimezone().isoformat()
|
||||
|
||||
PAYLOAD = {'apikey': configuration.tautulli_api_key, 'cmd': 'get_activity'}
|
||||
|
||||
ACTIVITY = requests.get('{}/api/v2'.format(configuration.tautulli_url),
|
||||
params=PAYLOAD).json()['response']['data']
|
||||
|
||||
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 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)
|
||||
|
||||
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)
|
||||
|
||||
return reader.city(ipaddress)
|
||||
|
||||
|
||||
INFLUX_PAYLOAD = [
|
||||
{
|
||||
"measurement": "Tautulli",
|
||||
"tags": {
|
||||
"type": "stream_count"
|
||||
},
|
||||
"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'])
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
for session in SESSIONS.keys():
|
||||
try:
|
||||
geodata = geo_lookup(SESSIONS[session]['ip_address_public'])
|
||||
except (ValueError, geoip2.errors.AddressNotFoundError):
|
||||
if configuration.tautulli_failback_ip:
|
||||
geodata = geo_lookup(configuration.tautulli_failback_ip)
|
||||
else:
|
||||
geodata = geo_lookup(requests.get('http://ip.42.pl/raw').text)
|
||||
|
||||
latitude = geodata.location.latitude
|
||||
|
||||
if not geodata.location.latitude:
|
||||
latitude = 37.234332396
|
||||
else:
|
||||
latitude = geodata.location.latitude
|
||||
|
||||
if not geodata.location.longitude:
|
||||
longitude = -115.80666344
|
||||
else:
|
||||
longitude = geodata.location.longitude
|
||||
|
||||
decision = SESSIONS[session]['transcode_decision']
|
||||
|
||||
if decision == 'copy':
|
||||
decision = 'direct stream'
|
||||
|
||||
video_decision = SESSIONS[session]['stream_video_decision']
|
||||
|
||||
if video_decision == 'copy':
|
||||
video_decision = 'direct stream'
|
||||
|
||||
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()
|
||||
|
||||
elif quality in ('SD', 'sd'):
|
||||
quality = SESSIONS[session]['stream_video_resolution'].upper()
|
||||
|
||||
elif quality in '4k':
|
||||
quality = SESSIONS[session]['stream_video_resolution'].upper()
|
||||
|
||||
else:
|
||||
quality = '{}p'.format(SESSIONS[session]['stream_video_resolution'])
|
||||
|
||||
|
||||
# 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",
|
||||
"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(),
|
||||
"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_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)
|
|
@ -1,4 +1,10 @@
|
|||
import os
|
||||
import time
|
||||
import tarfile
|
||||
import geoip2.database
|
||||
from typing import NamedTuple
|
||||
from os.path import abspath, join
|
||||
from urllib.request import urlretrieve
|
||||
|
||||
|
||||
class TVShow(NamedTuple):
|
||||
|
@ -35,17 +41,19 @@ class Queue(NamedTuple):
|
|||
protocol: str = None
|
||||
id: int = None
|
||||
|
||||
|
||||
class SonarrServer(NamedTuple):
|
||||
id: int = None
|
||||
url: str = None
|
||||
api_key: str = None
|
||||
verify_ssl: bool = False
|
||||
missing_days: int = 0
|
||||
missing_days_run_minutes: int = 30
|
||||
missing_days_run_seconds: int = 30
|
||||
future_days: int = 0
|
||||
future_days_run_minutes: int = 30
|
||||
future_days_run_seconds: int = 30
|
||||
queue: bool = False
|
||||
queue_run_minutes: int = 1
|
||||
queue_run_seconds: int = 1
|
||||
|
||||
|
||||
class Server(NamedTuple):
|
||||
id: int = None
|
||||
|
@ -55,14 +63,238 @@ class Server(NamedTuple):
|
|||
|
||||
|
||||
class TautulliServer(NamedTuple):
|
||||
id: int = None
|
||||
url: str = None
|
||||
fallback_ip: str = None
|
||||
apikey: str = None
|
||||
verify_ssl: bool = None
|
||||
influx_db: str = None
|
||||
get_activity: bool = False
|
||||
get_activity_run_seconds: int = 30
|
||||
get_sessions: bool = False
|
||||
get_sessions_run_seconds: int = 30
|
||||
|
||||
|
||||
class InfluxServer(NamedTuple):
|
||||
url: str = 'localhost'
|
||||
port: int = 8086
|
||||
username: str = 'root'
|
||||
password: str = 'root'
|
||||
password: str = 'root'
|
||||
|
||||
|
||||
class TautulliStream(NamedTuple):
|
||||
rating: str
|
||||
transcode_width: str
|
||||
labels: list
|
||||
stream_bitrate: str
|
||||
bandwidth: str
|
||||
optimized_version: int
|
||||
video_language: str
|
||||
parent_rating_key: str
|
||||
rating_key: str
|
||||
platform_version: str
|
||||
transcode_hw_decoding: int
|
||||
thumb: str
|
||||
title: str
|
||||
video_codec_level: str
|
||||
tagline: str
|
||||
last_viewed_at: str
|
||||
audio_sample_rate: str
|
||||
user_rating: str
|
||||
platform: str
|
||||
collections: list
|
||||
location: str
|
||||
transcode_container: str
|
||||
audio_channel_layout: str
|
||||
local: str
|
||||
stream_subtitle_format: str
|
||||
stream_video_ref_frames: str
|
||||
transcode_hw_encode_title: str
|
||||
stream_container_decision: str
|
||||
audience_rating: str
|
||||
full_title: str
|
||||
ip_address: str
|
||||
subtitles: int
|
||||
stream_subtitle_language: str
|
||||
channel_stream: int
|
||||
video_bitrate: str
|
||||
is_allow_sync: int
|
||||
stream_video_bitrate: str
|
||||
summary: str
|
||||
stream_audio_decision: str
|
||||
aspect_ratio: str
|
||||
audio_bitrate_mode: str
|
||||
transcode_hw_decode_title: str
|
||||
stream_audio_channel_layout: str
|
||||
deleted_user: int
|
||||
library_name: str
|
||||
art: str
|
||||
stream_video_resolution: str
|
||||
video_profile: str
|
||||
sort_title: str
|
||||
stream_video_codec_level: str
|
||||
stream_video_height: str
|
||||
year: str
|
||||
stream_duration: str
|
||||
stream_audio_channels: str
|
||||
video_language_code: str
|
||||
transcode_key: str
|
||||
transcode_throttled: int
|
||||
container: str
|
||||
stream_audio_bitrate: str
|
||||
user: str
|
||||
selected: int
|
||||
product_version: str
|
||||
subtitle_location: str
|
||||
transcode_hw_requested: int
|
||||
video_height: str
|
||||
state: str
|
||||
is_restricted: int
|
||||
email: str
|
||||
stream_container: str
|
||||
transcode_speed: str
|
||||
video_bit_depth: str
|
||||
stream_audio_sample_rate: str
|
||||
grandparent_title: str
|
||||
studio: str
|
||||
transcode_decision: str
|
||||
video_width: str
|
||||
bitrate: str
|
||||
machine_id: str
|
||||
originally_available_at: str
|
||||
video_frame_rate: str
|
||||
synced_version_profile: str
|
||||
friendly_name: str
|
||||
audio_profile: str
|
||||
optimized_version_title: str
|
||||
platform_name: str
|
||||
stream_video_language: str
|
||||
keep_history: int
|
||||
stream_audio_codec: str
|
||||
stream_video_codec: str
|
||||
grandparent_thumb: str
|
||||
synced_version: int
|
||||
transcode_hw_decode: str
|
||||
user_thumb: str
|
||||
stream_video_width: str
|
||||
height: str
|
||||
stream_subtitle_decision: str
|
||||
audio_codec: str
|
||||
parent_title: str
|
||||
guid: str
|
||||
audio_language_code: str
|
||||
transcode_video_codec: str
|
||||
transcode_audio_codec: str
|
||||
stream_video_decision: str
|
||||
user_id: int
|
||||
transcode_height: str
|
||||
transcode_hw_full_pipeline: int
|
||||
throttled: str
|
||||
quality_profile: str
|
||||
width: str
|
||||
live: int
|
||||
stream_subtitle_forced: int
|
||||
media_type: str
|
||||
video_resolution: str
|
||||
stream_subtitle_location: str
|
||||
do_notify: int
|
||||
video_ref_frames: str
|
||||
stream_subtitle_language_code: str
|
||||
audio_channels: str
|
||||
stream_audio_language_code: str
|
||||
optimized_version_profile: str
|
||||
relay: int
|
||||
duration: str
|
||||
rating_image: str
|
||||
is_home_user: int
|
||||
is_admin: int
|
||||
ip_address_public: str
|
||||
allow_guest: int
|
||||
transcode_audio_channels: str
|
||||
stream_audio_channel_layout_: str
|
||||
media_index: str
|
||||
stream_video_framerate: str
|
||||
transcode_hw_encode: str
|
||||
grandparent_rating_key: str
|
||||
original_title: str
|
||||
added_at: str
|
||||
banner: str
|
||||
bif_thumb: str
|
||||
parent_media_index: str
|
||||
live_uuid: str
|
||||
audio_language: str
|
||||
stream_audio_bitrate_mode: str
|
||||
username: str
|
||||
subtitle_decision: str
|
||||
children_count: str
|
||||
updated_at: str
|
||||
player: str
|
||||
subtitle_format: str
|
||||
file: str
|
||||
file_size: str
|
||||
session_key: str
|
||||
id: str
|
||||
subtitle_container: str
|
||||
genres: list
|
||||
stream_video_language_code: str
|
||||
indexes: int
|
||||
video_decision: str
|
||||
stream_audio_language: str
|
||||
writers: list
|
||||
actors: list
|
||||
progress_percent: str
|
||||
audio_decision: str
|
||||
subtitle_forced: int
|
||||
profile: str
|
||||
product: str
|
||||
view_offset: str
|
||||
type: str
|
||||
audience_rating_image: str
|
||||
audio_bitrate: str
|
||||
section_id: str
|
||||
stream_subtitle_codec: str
|
||||
subtitle_codec: str
|
||||
video_codec: str
|
||||
device: str
|
||||
stream_video_bit_depth: str
|
||||
video_framerate: str
|
||||
transcode_hw_encoding: int
|
||||
transcode_protocol: str
|
||||
shared_libraries: list
|
||||
stream_aspect_ratio: str
|
||||
content_rating: str
|
||||
session_id: str
|
||||
directors: list
|
||||
parent_thumb: str
|
||||
subtitle_language_code: str
|
||||
transcode_progress: int
|
||||
subtitle_language: str
|
||||
stream_subtitle_container: str
|
||||
|
||||
def geoip_download():
|
||||
tar_dbfile = abspath(join('..', 'data', 'GeoLite2-City.tar.gz'))
|
||||
url = 'http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz'
|
||||
urlretrieve(url, tar_dbfile)
|
||||
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__))))
|
||||
os.remove(tar_dbfile)
|
||||
|
||||
def geo_lookup(ipaddress):
|
||||
|
||||
dbfile = abspath(join('..', 'data', 'GeoLite2-City.mmdb'))
|
||||
now = time.time()
|
||||
|
||||
try:
|
||||
dbinfo = os.stat(dbfile)
|
||||
db_age = now - dbinfo.st_ctime
|
||||
if db_age > (35 * 86400):
|
||||
os.remove(dbfile)
|
||||
geoip_download()
|
||||
except FileNotFoundError:
|
||||
geoip_download()
|
||||
|
||||
reader = geoip2.database.Reader(dbfile)
|
||||
|
||||
return reader.city(ipaddress)
|
||||
|
|
|
@ -20,7 +20,7 @@ class INIParser(object):
|
|||
self.ombi_server = None
|
||||
|
||||
self.tautulli_enabled = False
|
||||
self.tautulli_server = None
|
||||
self.tautulli_servers = []
|
||||
|
||||
self.asa_enabled = False
|
||||
self.asa = None
|
||||
|
@ -67,9 +67,10 @@ class INIParser(object):
|
|||
future_days_run_seconds = self.config.getint(sonarr_section, 'future_days_run_seconds')
|
||||
queue_run_seconds = self.config.getint(sonarr_section, 'queue_run_seconds')
|
||||
|
||||
self.sonarr_servers.append(SonarrServer(server_id, scheme + url, apikey, verify_ssl, missing_days,
|
||||
missing_days_run_seconds, future_days,
|
||||
future_days_run_seconds, queue, queue_run_seconds))
|
||||
server = SonarrServer(server_id, scheme + url, apikey, verify_ssl, missing_days,
|
||||
missing_days_run_seconds, future_days, future_days_run_seconds,
|
||||
queue, queue_run_seconds)
|
||||
self.sonarr_servers.append(server)
|
||||
|
||||
# Parse Radarr options
|
||||
try:
|
||||
|
@ -79,6 +80,8 @@ class INIParser(object):
|
|||
self.radarr_enabled = True
|
||||
except ValueError:
|
||||
self.radarr_enabled = True
|
||||
|
||||
if self.sonarr_enabled:
|
||||
sids = self.config.get('global', 'radarr_server_ids').strip(' ').split(',')
|
||||
|
||||
for server_id in sids:
|
||||
|
@ -91,16 +94,32 @@ class INIParser(object):
|
|||
self.radarr_servers.append(Server(server_id, scheme + url, apikey, verify_ssl))
|
||||
|
||||
# Parse Tautulli options
|
||||
if self.config.getboolean('global', 'tautulli'):
|
||||
try:
|
||||
if not self.config.getboolean('global', 'tautulli_server_ids'):
|
||||
sys.exit('tautulli_server_ids must be either false, or a comma-separated list of server ids')
|
||||
elif self.config.getint('global', 'tautulli_server_ids'):
|
||||
self.tautulli_enabled = True
|
||||
except ValueError:
|
||||
self.tautulli_enabled = True
|
||||
url = self.config.get('tautulli', 'url')
|
||||
fallback_ip = self.config.get('tautulli', 'fallback_ip')
|
||||
apikey = self.config.get('tautulli', 'apikey')
|
||||
scheme = 'https://' if self.config.getboolean('tautulli', 'ssl') else 'http://'
|
||||
verify_ssl = self.config.getboolean('tautulli', 'verify_ssl')
|
||||
db_name = self.config.get('tautulli', 'influx_db')
|
||||
|
||||
self.tautulli_server = TautulliServer(scheme + url, fallback_ip, apikey, verify_ssl, db_name)
|
||||
if self.tautulli_enabled:
|
||||
sids = self.config.get('global', 'tautulli_server_ids').strip(' ').split(',')
|
||||
|
||||
for server_id in sids:
|
||||
tautulli_section = 'tautulli-' + server_id
|
||||
url = self.config.get(tautulli_section, 'url')
|
||||
fallback_ip = self.config.get(tautulli_section, 'fallback_ip')
|
||||
apikey = self.config.get(tautulli_section, 'apikey')
|
||||
scheme = 'https://' if self.config.getboolean(tautulli_section, 'ssl') else 'http://'
|
||||
verify_ssl = self.config.getboolean(tautulli_section, 'verify_ssl')
|
||||
get_activity = self.config.getboolean(tautulli_section, 'get_activity')
|
||||
get_activity_run_seconds = self.config.getint(tautulli_section, 'get_activity_run_seconds')
|
||||
get_sessions = self.config.getboolean(tautulli_section, 'get_sessions')
|
||||
get_sessions_run_seconds = self.config.getint(tautulli_section, 'get_sessions_run_seconds')
|
||||
|
||||
server = TautulliServer(server_id, scheme + url, fallback_ip, apikey, verify_ssl, get_activity,
|
||||
get_activity_run_seconds, get_sessions, get_sessions_run_seconds)
|
||||
self.tautulli_servers.append(server)
|
||||
|
||||
# Parse Ombi Options
|
||||
if self.config.getboolean('global', 'ombi'):
|
||||
|
|
|
@ -9,13 +9,13 @@ from Varken.helpers import TVShow, Queue
|
|||
|
||||
|
||||
class SonarrAPI(object):
|
||||
def __init__(self, sonarr_servers, influx_server):
|
||||
def __init__(self, servers, influx_server):
|
||||
# Set Time of initialization
|
||||
self.now = datetime.now(timezone.utc).astimezone().isoformat()
|
||||
self.today = str(date.today())
|
||||
self.influx = InfluxDBClient(influx_server.url, influx_server.port, influx_server.username,
|
||||
influx_server.password, 'plex')
|
||||
self.servers = sonarr_servers
|
||||
self.servers = servers
|
||||
# Create session to reduce server web thread load, and globally define pageSize for all requests
|
||||
self.session = requests.Session()
|
||||
self.session.params = {'pageSize': 1000}
|
||||
|
|
146
Varken/tautulli.py
Normal file
146
Varken/tautulli.py
Normal file
|
@ -0,0 +1,146 @@
|
|||
from datetime import datetime, timezone
|
||||
from geoip2.errors import AddressNotFoundError
|
||||
from influxdb import InfluxDBClient
|
||||
import requests
|
||||
from Varken.helpers import TautulliStream, geo_lookup
|
||||
from Varken.logger import logging
|
||||
|
||||
class TautulliAPI(object):
|
||||
def __init__(self, servers, influx_server):
|
||||
# Set Time of initialization
|
||||
self.now = datetime.now(timezone.utc).astimezone().isoformat()
|
||||
self.influx = InfluxDBClient(influx_server.url, influx_server.port, influx_server.username,
|
||||
influx_server.password, 'plex')
|
||||
self.servers = servers
|
||||
self.session = requests.Session()
|
||||
self.endpoint = '/api/v2'
|
||||
|
||||
def influx_push(self, payload):
|
||||
# TODO: error handling for failed connection
|
||||
self.influx.write_points(payload)
|
||||
|
||||
@logging
|
||||
def get_activity(self, notimplemented):
|
||||
params = {'cmd': 'get_activity'}
|
||||
influx_payload = []
|
||||
|
||||
for server in self.servers:
|
||||
params['apikey'] = server.apikey
|
||||
g = self.session.get(server.url + self.endpoint, params=params, verify=server.verify_ssl)
|
||||
get = g.json()['response']['data']
|
||||
|
||||
influx_payload.append(
|
||||
{
|
||||
"measurement": "Tautulli",
|
||||
"tags": {
|
||||
"type": "current_stream_stats",
|
||||
"server": server.id
|
||||
},
|
||||
"time": self.now,
|
||||
"fields": {
|
||||
"stream_count": int(get['stream_count']),
|
||||
"total_bandwidth": int(get['total_bandwidth']),
|
||||
"wan_bandwidth": int(get['wan_bandwidth']),
|
||||
"lan_bandwidth": int(get['lan_bandwidth']),
|
||||
"transcode_streams": int(get['stream_count_transcode']),
|
||||
"direct_play_streams": int(get['stream_count_direct_play']),
|
||||
"direct_streams": int(get['stream_count_direct_stream'])
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
self.influx_push(influx_payload)
|
||||
|
||||
@logging
|
||||
def get_sessions(self, notimplemented):
|
||||
params = {'cmd': 'get_activity'}
|
||||
influx_payload = []
|
||||
|
||||
for server in self.servers:
|
||||
params['apikey'] = server.apikey
|
||||
g = self.session.get(server.url + self.endpoint, params=params, verify=server.verify_ssl)
|
||||
get = g.json()['response']['data']['sessions']
|
||||
print(get)
|
||||
sessions = [TautulliStream(**session) for session in get]
|
||||
|
||||
for session in sessions:
|
||||
try:
|
||||
geodata = geo_lookup(session.ip_address_public)
|
||||
except (ValueError, AddressNotFoundError):
|
||||
if server.fallback_ip:
|
||||
geodata = geo_lookup(server.fallback_ip)
|
||||
else:
|
||||
my_ip = requests.get('http://ip.42.pl/raw').text
|
||||
geodata = geo_lookup(my_ip)
|
||||
|
||||
if not all([geodata.location.latitude, geodata.location.longitude]):
|
||||
latitude = 37.234332396
|
||||
longitude = -115.80666344
|
||||
else:
|
||||
latitude = geodata.location.latitude
|
||||
longitude = geodata.location.longitude
|
||||
|
||||
decision = session.transcode_decision
|
||||
if decision == 'copy':
|
||||
decision = 'direct stream'
|
||||
|
||||
video_decision = session.stream_video_decision
|
||||
if video_decision == 'copy':
|
||||
video_decision = 'direct stream'
|
||||
elif video_decision == '':
|
||||
video_decision = 'Music'
|
||||
|
||||
quality = session.stream_video_resolution
|
||||
if not quality:
|
||||
quality = session.container.upper()
|
||||
elif quality in ('SD', 'sd', '4k'):
|
||||
quality = session.stream_video_resolution.upper()
|
||||
else:
|
||||
quality = session.stream_video_resolution + 'p'
|
||||
|
||||
player_state = 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",
|
||||
"session_id": session.session_id,
|
||||
"name": session.friendly_name,
|
||||
"title": session.full_title,
|
||||
"platform": session.platform,
|
||||
"product_version": session.product_version,
|
||||
"quality": quality,
|
||||
"video_decision": video_decision.title(),
|
||||
"transcode_decision": decision.title(),
|
||||
"media_type": session.media_type.title(),
|
||||
"audio_codec": session.audio_codec.upper(),
|
||||
"audio_profile": session.audio_profile.upper(),
|
||||
"stream_audio_codec": session.stream_audio_codec.upper(),
|
||||
"quality_profile": session.quality_profile,
|
||||
"progress_percent": 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": session.platform,
|
||||
"server": server.id
|
||||
},
|
||||
"time": self.now,
|
||||
"fields": {
|
||||
"session_id": session.session_id,
|
||||
"session_key": session.session_key
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
self.influx_push(influx_payload)
|
|
@ -4,6 +4,7 @@ from time import sleep
|
|||
|
||||
from Varken.iniparser import INIParser
|
||||
from Varken.sonarr import SonarrAPI
|
||||
from Varken.tautulli import TautulliAPI
|
||||
|
||||
|
||||
def threaded(job, days=None):
|
||||
|
@ -27,6 +28,15 @@ if __name__ == "__main__":
|
|||
schedule.every(server.future_days_run_seconds).seconds.do(threaded, SONARR.get_future,
|
||||
server.future_days)
|
||||
|
||||
if CONFIG.tautulli_enabled:
|
||||
TAUTULLI = TautulliAPI(CONFIG.tautulli_servers, CONFIG.influx_server)
|
||||
|
||||
for server in CONFIG.tautulli_servers:
|
||||
if server.get_activity:
|
||||
schedule.every(server.get_activity_run_seconds).seconds.do(threaded, TAUTULLI.get_activity)
|
||||
if server.get_sessions:
|
||||
schedule.every(server.get_sessions_run_seconds).seconds.do(threaded, TAUTULLI.get_sessions)
|
||||
|
||||
while True:
|
||||
schedule.run_pending()
|
||||
sleep(1)
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
[global]
|
||||
sonarr_server_ids = 1,2
|
||||
radarr_server_ids = 1,2
|
||||
tautulli_server_ids = 1
|
||||
ombi = true
|
||||
tautulli = true
|
||||
asa = false
|
||||
|
||||
[influxdb]
|
||||
|
@ -18,6 +18,17 @@ port = 8086
|
|||
username = root
|
||||
password = root
|
||||
|
||||
[tautulli-1]
|
||||
url = tautulli.domain.tld
|
||||
fallback_ip = 0.0.0.0
|
||||
apikey = xxxxxxxxxxxxxxxx
|
||||
ssl = false
|
||||
verify_ssl = true
|
||||
get_activity = true
|
||||
get_activity_run_seconds = 30
|
||||
get_sessions = true
|
||||
get_sessions_run_seconds = 30
|
||||
|
||||
[sonarr-1]
|
||||
url = sonarr1.domain.tld
|
||||
apikey = xxxxxxxxxxxxxxxx
|
||||
|
@ -60,12 +71,6 @@ apikey = xxxxxxxxxxxxxxxx
|
|||
ssl = false
|
||||
verify_ssl = true
|
||||
|
||||
[tautulli]
|
||||
url = tautulli.domain.tld
|
||||
fallback_ip = 0.0.0.0
|
||||
apikey = xxxxxxxxxxxxxxxx
|
||||
ssl = false
|
||||
verify_ssl = true
|
||||
|
||||
[asa]
|
||||
url = firewall.domain.tld
|
||||
|
|
Loading…
Reference in a new issue