v1.5 Merge
This commit is contained in:
commit
d9637aca73
12 changed files with 524 additions and 414 deletions
30
CHANGELOG.md
30
CHANGELOG.md
|
@ -1,6 +1,25 @@
|
|||
# Change Log
|
||||
|
||||
## [v1.4](https://github.com/Boerderij/Varken/tree/v1.4) (2018-12-18)
|
||||
## [v1.5](https://github.com/Boerderij/Varken/tree/v1.5) (2018-12-30)
|
||||
[Full Changelog](https://github.com/Boerderij/Varken/compare/v1.4...v1.5)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- \[Feature Request\] Add issues from Ombi [\#70](https://github.com/Boerderij/Varken/issues/70)
|
||||
- \[Feature Request\] Allow DNS Hostnames [\#66](https://github.com/Boerderij/Varken/issues/66)
|
||||
- Replace static grafana configs with a Public Example [\#32](https://github.com/Boerderij/Varken/issues/32)
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- \[BUG\] unexpected keyword argument 'channel\_icon' [\#73](https://github.com/Boerderij/Varken/issues/73)
|
||||
- \[BUG\] Unexpected keyword argument 'addOptions' [\#68](https://github.com/Boerderij/Varken/issues/68)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- v1.5 Merge [\#75](https://github.com/Boerderij/Varken/pull/75) ([DirtyCajunRice](https://github.com/DirtyCajunRice))
|
||||
- Add Ombi Issues [\#74](https://github.com/Boerderij/Varken/pull/74) ([anderssonoscar0](https://github.com/anderssonoscar0))
|
||||
|
||||
## [v1.4](https://github.com/Boerderij/Varken/tree/v1.4) (2018-12-19)
|
||||
[Full Changelog](https://github.com/Boerderij/Varken/compare/v1.3-nightly...v1.4)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
@ -92,10 +111,6 @@
|
|||
## [v0.2-nightly](https://github.com/Boerderij/Varken/tree/v0.2-nightly) (2018-12-06)
|
||||
[Full Changelog](https://github.com/Boerderij/Varken/compare/v0.1...v0.2-nightly)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Tautulli - multiple server support? [\#25](https://github.com/Boerderij/Varken/issues/25)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Create the DB if it does not exist. [\#38](https://github.com/Boerderij/Varken/issues/38)
|
||||
|
@ -105,7 +120,12 @@
|
|||
- use a config.ini instead of command-line flags [\#33](https://github.com/Boerderij/Varken/issues/33)
|
||||
- Migrate crontab to python schedule package [\#31](https://github.com/Boerderij/Varken/issues/31)
|
||||
- Consolidate missing and missing\_days in sonarr.py [\#30](https://github.com/Boerderij/Varken/issues/30)
|
||||
- Database Withou any scripts [\#29](https://github.com/Boerderij/Varken/issues/29)
|
||||
- Grafana dashboard json doesn't match format of readme screenshot? [\#28](https://github.com/Boerderij/Varken/issues/28)
|
||||
- Ombi something new \[Request\] [\#26](https://github.com/Boerderij/Varken/issues/26)
|
||||
- Users Online not populating [\#24](https://github.com/Boerderij/Varken/issues/24)
|
||||
- Missing dashboard [\#23](https://github.com/Boerderij/Varken/issues/23)
|
||||
- Is there a Docker Image available for these scripts? [\#22](https://github.com/Boerderij/Varken/issues/22)
|
||||
- Support for Linux without ASA [\#21](https://github.com/Boerderij/Varken/issues/21)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
|
19
README.md
19
README.md
|
@ -10,14 +10,14 @@ from the Plex ecosystem into InfluxDB. Examples use Grafana for a
|
|||
frontend
|
||||
|
||||
Requirements:
|
||||
* Python3.6+
|
||||
* Python3.6.7+
|
||||
* Python3-pip
|
||||
* [InfluxDB](https://www.influxdata.com/)
|
||||
|
||||
<p align="center">
|
||||
Example Dashboard
|
||||
|
||||
<img width="800" src="https://nickflix.io/sharex/firefox_NxdrqisVLF.png">
|
||||
<img width="800" src="https://i.imgur.com/G5bnpjs.png">
|
||||
</p>
|
||||
|
||||
Supported Modules:
|
||||
|
@ -103,9 +103,16 @@ do not include database creation, please ensure you create an influx database
|
|||
named `varken`
|
||||
|
||||
### Grafana
|
||||
[Grafana Installation Documentation](http://docs.grafana.org/installation/)
|
||||
[Grafana Installation Documentation](http://docs.grafana.org/installation/)
|
||||
[Official Example Dashboards](https://grafana.com/dashboards?search=Varken%20%5BOfficial%5D)
|
||||
|
||||
Grafana is used in our examples but not required, nor packaged as part of
|
||||
Varken. Panel example pictures are pinned in the grafana-panels channel of
|
||||
discord. Future releases may contain a json-generator, but it does not exist
|
||||
as varken stands today.
|
||||
Varken. Panel examples now exist in both nightly and tagged releases hosted
|
||||
on grafana.com (link above).
|
||||
|
||||
1. Use the link above, then click on your desired dashboard version
|
||||
2. Click `Copy ID to Clipboard`
|
||||
3. In grafana, click your dashboards menu dropdown, and then click `Import dashboard`
|
||||
4. Paste the ID into the `Grafana.com Dashboard` field and then click into empty space on the screen. (This should change the screen to show `Importing Dashboard from Grafana.com`
|
||||
5. Select your varken datasource name in the dropdown labeled `Varken`
|
||||
6. Click Import!
|
|
@ -121,6 +121,8 @@ if __name__ == "__main__":
|
|||
schedule.every(server.request_type_run_seconds).seconds.do(threaded, OMBI.get_request_counts)
|
||||
if server.request_total_counts:
|
||||
schedule.every(server.request_total_run_seconds).seconds.do(threaded, OMBI.get_all_requests)
|
||||
if server.issue_status_counts:
|
||||
schedule.every(server.issue_status_run_seconds).seconds.do(threaded, OMBI.get_issue_counts)
|
||||
|
||||
if CONFIG.sickchill_enabled:
|
||||
for server in CONFIG.sickchill_servers:
|
||||
|
|
|
@ -2,26 +2,28 @@
|
|||
# - Sonarr + Radarr scripts support multiple servers. You can remove the second
|
||||
# server by putting a # in front of the lines and section name, and removing
|
||||
# that number from your server_ids list
|
||||
# - fallback_ip, This is used when there is no IP listed in tautulli.
|
||||
# This can happen when you are streaming locally. This is usually your public IP.
|
||||
# - fallback_ip, This is used when there is no IP listed in Tautulli.
|
||||
# This can happen when you are streaming locally. Set this to your public IP.
|
||||
# You do not need to change this value if your IP changes. This is only for
|
||||
# location lookups when there is a failure.
|
||||
|
||||
[global]
|
||||
sonarr_server_ids = 1,2
|
||||
radarr_server_ids = 1,2
|
||||
tautulli_server_ids = 1
|
||||
ombi_server_ids = 1
|
||||
ciscoasa_firewall_ids = false
|
||||
ciscoasa_server_ids = false
|
||||
sickchill_server_ids = false
|
||||
|
||||
[influxdb]
|
||||
url = influxdb.domain.tld
|
||||
port = 8086
|
||||
username =
|
||||
password =
|
||||
username = root
|
||||
password = root
|
||||
|
||||
[tautulli-1]
|
||||
url = tautulli.domain.tld:8181
|
||||
fallback_ip = 0.0.0.0
|
||||
fallback_ip = 1.1.1.1
|
||||
apikey = xxxxxxxxxxxxxxxx
|
||||
ssl = false
|
||||
verify_ssl = false
|
||||
|
@ -83,6 +85,8 @@ get_request_type_counts = true
|
|||
request_type_run_seconds = 300
|
||||
get_request_total_counts = true
|
||||
request_total_run_seconds = 300
|
||||
get_issue_status_counts = true
|
||||
issue_status_run_seconds = 300
|
||||
|
||||
[sickchill-1]
|
||||
url = sickchill.domain.tld:8081
|
||||
|
@ -92,8 +96,6 @@ verify_ssl = false
|
|||
get_missing = true
|
||||
get_missing_run_seconds = 300
|
||||
|
||||
|
||||
|
||||
[ciscoasa-1]
|
||||
url = firewall.domain.tld
|
||||
username = cisco
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
VERSION = 1.4
|
||||
VERSION = 1.5
|
||||
BRANCH = 'master'
|
||||
|
|
|
@ -27,17 +27,20 @@ class GeoIPHandler(object):
|
|||
|
||||
def lookup(self, ipaddress):
|
||||
ip = ipaddress
|
||||
self.logger.debug('Getting lat/long for Tautulli stream')
|
||||
self.logger.debug('Getting lat/long for Tautulli stream using ip with last octet ending in %s',
|
||||
ip.split('.')[-1:])
|
||||
return self.reader.city(ip)
|
||||
|
||||
def update(self):
|
||||
today = date.today()
|
||||
dbdate = None
|
||||
|
||||
try:
|
||||
dbdate = date.fromtimestamp(stat(self.dbfile).st_ctime)
|
||||
except FileNotFoundError:
|
||||
self.logger.error("Could not find GeoLite2 DB as: %s", self.dbfile)
|
||||
self.download()
|
||||
dbdate = date.fromtimestamp(stat(self.dbfile).st_ctime)
|
||||
|
||||
first_wednesday_day = [week[2:3][0] for week in monthcalendar(today.year, today.month) if week[2:3][0] != 0][0]
|
||||
first_wednesday_date = date(today.year, today.month, first_wednesday_day)
|
||||
|
||||
|
@ -52,7 +55,6 @@ class GeoIPHandler(object):
|
|||
else:
|
||||
self.logger.debug('Geolite2 DB will update in %s days', abs(td.days))
|
||||
|
||||
|
||||
def download(self):
|
||||
tar_dbfile = abspath(join(self.data_folder, 'GeoLite2-City.tar.gz'))
|
||||
url = 'http://geolite.maxmind.com/download/geoip/database/GeoLite2-City.tar.gz'
|
||||
|
|
|
@ -59,15 +59,17 @@ class INIParser(object):
|
|||
self.logger.error('Config file missing (varken.ini) in %s', self.data_folder)
|
||||
exit(1)
|
||||
|
||||
def url_check(self, url=None, include_port=True):
|
||||
def url_check(self, url=None, include_port=True, section=None):
|
||||
url_check = url
|
||||
module = section
|
||||
inc_port = include_port
|
||||
|
||||
search = (r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' # domain...
|
||||
search = (r'(?:([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}|' # domain...
|
||||
r'localhost|' # localhost...
|
||||
r'^[a-zA-Z0-9_-]*|' # hostname only. My soul dies a little every time this is used...
|
||||
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
|
||||
)
|
||||
|
||||
# Include search for port if it is needed.
|
||||
if inc_port:
|
||||
search = (search + r'(?::\d+)?' + r'(?:/?|[/?]\S+)$')
|
||||
else:
|
||||
|
@ -78,28 +80,28 @@ class INIParser(object):
|
|||
valid = match(regex, url_check) is not None
|
||||
if not valid:
|
||||
if inc_port:
|
||||
self.logger.error('%s is invalid! URL must host/IP and port if not 80 or 443. ie. localhost:8080',
|
||||
url_check)
|
||||
self.logger.error('%s is invalid in module [%s]! URL must host/IP and '
|
||||
'port if not 80 or 443. ie. localhost:8080',
|
||||
url_check, module)
|
||||
exit(1)
|
||||
else:
|
||||
self.logger.error('%s is invalid! URL must host/IP. ie. localhost', url_check)
|
||||
self.logger.error('%s is invalid in module [%s]! URL must host/IP. ie. localhost', url_check, module)
|
||||
exit(1)
|
||||
else:
|
||||
self.logger.debug('%s is a valid URL in the config.', url_check)
|
||||
self.logger.debug('%s is a valid URL in module [%s].', url_check, module)
|
||||
return url_check
|
||||
|
||||
def parse_opts(self):
|
||||
self.read_file()
|
||||
# Parse InfluxDB options
|
||||
url = self.url_check(self.config.get('influxdb', 'url'), include_port=False)
|
||||
url = self.url_check(self.config.get('influxdb', 'url'), include_port=False, section='influxdb')
|
||||
|
||||
port = self.config.getint('influxdb', 'port')
|
||||
|
||||
username = self.config.get('influxdb', 'username')
|
||||
|
||||
password = self.config.get('influxdb', 'password')
|
||||
|
||||
self.influx_server = InfluxServer(url, port, username, password)
|
||||
self.influx_server = InfluxServer(url=url, port=port, username=username, password=password)
|
||||
|
||||
# Check for all enabled services
|
||||
for service in self.services:
|
||||
|
@ -111,7 +113,7 @@ class INIParser(object):
|
|||
server = None
|
||||
section = f"{service}-{server_id}"
|
||||
try:
|
||||
url = self.url_check(self.config.get(section, 'url'))
|
||||
url = self.url_check(self.config.get(section, 'url'), section=section)
|
||||
|
||||
apikey = None
|
||||
if service != 'ciscoasa':
|
||||
|
@ -137,9 +139,11 @@ class INIParser(object):
|
|||
|
||||
queue_run_seconds = self.config.getint(section, '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)
|
||||
server = SonarrServer(id=server_id, url=scheme + url, api_key=apikey, verify_ssl=verify_ssl,
|
||||
missing_days=missing_days, future_days=future_days,
|
||||
missing_days_run_seconds=missing_days_run_seconds,
|
||||
future_days_run_seconds=future_days_run_seconds,
|
||||
queue=queue, queue_run_seconds=queue_run_seconds)
|
||||
|
||||
if service == 'radarr':
|
||||
queue = self.config.getboolean(section, 'queue')
|
||||
|
@ -150,8 +154,9 @@ class INIParser(object):
|
|||
|
||||
get_missing_run_seconds = self.config.getint(section, 'get_missing_run_seconds')
|
||||
|
||||
server = RadarrServer(server_id, scheme + url, apikey, verify_ssl, queue, queue_run_seconds,
|
||||
get_missing, get_missing_run_seconds)
|
||||
server = RadarrServer(id=server_id, url=scheme + url, api_key=apikey, verify_ssl=verify_ssl,
|
||||
queue_run_seconds=queue_run_seconds, get_missing=get_missing,
|
||||
queue=queue, get_missing_run_seconds=get_missing_run_seconds)
|
||||
|
||||
if service == 'tautulli':
|
||||
fallback_ip = self.config.get(section, 'fallback_ip')
|
||||
|
@ -164,9 +169,11 @@ class INIParser(object):
|
|||
|
||||
get_stats_run_seconds = self.config.getint(section, 'get_stats_run_seconds')
|
||||
|
||||
server = TautulliServer(server_id, scheme + url, fallback_ip, apikey, verify_ssl,
|
||||
get_activity, get_activity_run_seconds, get_stats,
|
||||
get_stats_run_seconds)
|
||||
server = TautulliServer(id=server_id, url=scheme + url, api_key=apikey,
|
||||
verify_ssl=verify_ssl, get_activity=get_activity,
|
||||
fallback_ip=fallback_ip, get_stats=get_stats,
|
||||
get_activity_run_seconds=get_activity_run_seconds,
|
||||
get_stats_run_seconds=get_stats_run_seconds)
|
||||
|
||||
if service == 'ombi':
|
||||
request_type_counts = self.config.getboolean(section, 'get_request_type_counts')
|
||||
|
@ -177,17 +184,26 @@ class INIParser(object):
|
|||
|
||||
request_total_run_seconds = self.config.getint(section, 'request_total_run_seconds')
|
||||
|
||||
server = OmbiServer(server_id, scheme + url, apikey, verify_ssl, request_type_counts,
|
||||
request_type_run_seconds, request_total_counts,
|
||||
request_total_run_seconds)
|
||||
issue_status_counts = self.config.getboolean(section, 'get_issue_status_counts')
|
||||
|
||||
issue_status_run_seconds = self.config.getint(section, 'issue_status_run_seconds')
|
||||
|
||||
server = OmbiServer(id=server_id, url=scheme + url, api_key=apikey, verify_ssl=verify_ssl,
|
||||
request_type_counts=request_type_counts,
|
||||
request_type_run_seconds=request_type_run_seconds,
|
||||
request_total_counts=request_total_counts,
|
||||
request_total_run_seconds=request_total_run_seconds,
|
||||
issue_status_counts=issue_status_counts,
|
||||
issue_status_run_seconds=issue_status_run_seconds)
|
||||
|
||||
if service == 'sickchill':
|
||||
get_missing = self.config.getboolean(section, 'get_missing')
|
||||
|
||||
get_missing_run_seconds = self.config.getint(section, 'get_missing_run_seconds')
|
||||
|
||||
server = SickChillServer(server_id, scheme + url, apikey, verify_ssl,
|
||||
get_missing, get_missing_run_seconds)
|
||||
server = SickChillServer(id=server_id, url=scheme + url, api_key=apikey,
|
||||
verify_ssl=verify_ssl, get_missing=get_missing,
|
||||
get_missing_run_seconds=get_missing_run_seconds)
|
||||
|
||||
if service == 'ciscoasa':
|
||||
username = self.config.get(section, 'username')
|
||||
|
@ -198,8 +214,10 @@ class INIParser(object):
|
|||
|
||||
get_bandwidth_run_seconds = self.config.getint(section, 'get_bandwidth_run_seconds')
|
||||
|
||||
server = CiscoASAFirewall(server_id, scheme + url, username, password, outside_interface,
|
||||
verify_ssl, get_bandwidth_run_seconds)
|
||||
server = CiscoASAFirewall(id=server_id, url=scheme + url, verify_ssl=verify_ssl,
|
||||
username=username, password=password,
|
||||
outside_interface=outside_interface,
|
||||
get_bandwidth_run_seconds=get_bandwidth_run_seconds)
|
||||
|
||||
getattr(self, f'{service}_servers').append(server)
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ from requests import Session, Request
|
|||
from datetime import datetime, timezone
|
||||
|
||||
from varken.helpers import connection_handler, hashit
|
||||
from varken.structures import OmbiRequestCounts, OmbiMovieRequest, OmbiTVRequest
|
||||
from varken.structures import OmbiRequestCounts, OmbiIssuesCounts, OmbiMovieRequest, OmbiTVRequest
|
||||
|
||||
|
||||
class OmbiAPI(object):
|
||||
|
@ -65,14 +65,17 @@ class OmbiAPI(object):
|
|||
# Request Type: Movie = 1, TV Show = 0
|
||||
for movie in movie_requests:
|
||||
hash_id = hashit(f'{movie.id}{movie.theMovieDbId}{movie.title}')
|
||||
status = None
|
||||
|
||||
# Denied = 0, Approved = 1, Completed = 2, Pending = 3
|
||||
if movie.denied:
|
||||
status = 0
|
||||
|
||||
elif movie.approved and movie.available:
|
||||
status = 2
|
||||
|
||||
elif movie.approved:
|
||||
status = 1
|
||||
|
||||
else:
|
||||
status = 3
|
||||
|
||||
|
@ -101,10 +104,13 @@ class OmbiAPI(object):
|
|||
# Denied = 0, Approved = 1, Completed = 2, Pending = 3
|
||||
if show.childRequests[0]['denied']:
|
||||
status = 0
|
||||
|
||||
elif show.childRequests[0]['approved'] and show.childRequests[0]['available']:
|
||||
status = 2
|
||||
|
||||
elif show.childRequests[0]['approved']:
|
||||
status = 1
|
||||
|
||||
else:
|
||||
status = 3
|
||||
|
||||
|
@ -156,3 +162,31 @@ class OmbiAPI(object):
|
|||
]
|
||||
|
||||
self.dbmanager.write_points(influx_payload)
|
||||
|
||||
def get_issue_counts(self):
|
||||
now = datetime.now(timezone.utc).astimezone().isoformat()
|
||||
endpoint = '/api/v1/Issues/count'
|
||||
|
||||
req = self.session.prepare_request(Request('GET', self.server.url + endpoint))
|
||||
get = connection_handler(self.session, req, self.server.verify_ssl)
|
||||
|
||||
if not get:
|
||||
return
|
||||
|
||||
requests = OmbiIssuesCounts(**get)
|
||||
influx_payload = [
|
||||
{
|
||||
"measurement": "Ombi",
|
||||
"tags": {
|
||||
"type": "Issues_Counts"
|
||||
},
|
||||
"time": now,
|
||||
"fields": {
|
||||
"pending": requests.pending,
|
||||
"in_progress": requests.inProgress,
|
||||
"resolved": requests.resolved
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
self.dbmanager.write_points(influx_payload)
|
||||
|
|
|
@ -2,7 +2,7 @@ from logging import getLogger
|
|||
from requests import Session, Request
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from varken.structures import Movie, Queue
|
||||
from varken.structures import RadarrMovie, Queue
|
||||
from varken.helpers import hashit, connection_handler
|
||||
|
||||
|
||||
|
@ -31,9 +31,9 @@ class RadarrAPI(object):
|
|||
return
|
||||
|
||||
try:
|
||||
movies = [Movie(**movie) for movie in get]
|
||||
movies = [RadarrMovie(**movie) for movie in get]
|
||||
except TypeError as e:
|
||||
self.logger.error('TypeError has occurred : %s while creating Movie structure', e)
|
||||
self.logger.error('TypeError has occurred : %s while creating RadarrMovie structure', e)
|
||||
return
|
||||
|
||||
for movie in movies:
|
||||
|
@ -82,9 +82,9 @@ class RadarrAPI(object):
|
|||
|
||||
for movie in get:
|
||||
try:
|
||||
movie['movie'] = Movie(**movie['movie'])
|
||||
movie['movie'] = RadarrMovie(**movie['movie'])
|
||||
except TypeError as e:
|
||||
self.logger.error('TypeError has occurred : %s while creating Movie structure', e)
|
||||
self.logger.error('TypeError has occurred : %s while creating RadarrMovie structure', e)
|
||||
return
|
||||
|
||||
try:
|
||||
|
|
|
@ -2,7 +2,7 @@ from logging import getLogger
|
|||
from requests import Session, Request
|
||||
from datetime import datetime, timezone, date, timedelta
|
||||
|
||||
from varken.structures import Queue, TVShow
|
||||
from varken.structures import Queue, SonarrTVShow
|
||||
from varken.helpers import hashit, connection_handler
|
||||
|
||||
|
||||
|
@ -34,11 +34,11 @@ class SonarrAPI(object):
|
|||
if not get:
|
||||
return
|
||||
|
||||
# Iteratively create a list of TVShow Objects from response json
|
||||
# Iteratively create a list of SonarrTVShow Objects from response json
|
||||
try:
|
||||
tv_shows = [TVShow(**show) for show in get]
|
||||
tv_shows = [SonarrTVShow(**show) for show in get]
|
||||
except TypeError as e:
|
||||
self.logger.error('TypeError has occurred : %s while creating TVShow structure', e)
|
||||
self.logger.error('TypeError has occurred : %s while creating SonarrTVShow structure', e)
|
||||
return
|
||||
|
||||
# Add show to missing list if file does not exist
|
||||
|
@ -87,9 +87,9 @@ class SonarrAPI(object):
|
|||
return
|
||||
|
||||
try:
|
||||
tv_shows = [TVShow(**show) for show in get]
|
||||
tv_shows = [SonarrTVShow(**show) for show in get]
|
||||
except TypeError as e:
|
||||
self.logger.error('TypeError has occurred : %s while creating TVShow structure', e)
|
||||
self.logger.error('TypeError has occurred : %s while creating SonarrTVShow structure', e)
|
||||
return
|
||||
|
||||
for show in tv_shows:
|
||||
|
@ -150,9 +150,9 @@ class SonarrAPI(object):
|
|||
protocol_id = 0
|
||||
|
||||
queue.append((show.series['title'], show.episode['title'], show.protocol.upper(),
|
||||
protocol_id, sxe, show.id))
|
||||
protocol_id, sxe, show.id, show.quality['quality']['name']))
|
||||
|
||||
for series_title, episode_title, protocol, protocol_id, sxe, sonarr_id in queue:
|
||||
for series_title, episode_title, protocol, protocol_id, sxe, sonarr_id, quality in queue:
|
||||
hash_id = hashit(f'{self.server.id}{series_title}{sxe}')
|
||||
influx_payload.append(
|
||||
{
|
||||
|
@ -165,7 +165,8 @@ class SonarrAPI(object):
|
|||
"epname": episode_title,
|
||||
"sxe": sxe,
|
||||
"protocol": protocol,
|
||||
"protocol_id": protocol_id
|
||||
"protocol_id": protocol_id,
|
||||
"quality": quality
|
||||
},
|
||||
"time": now,
|
||||
"fields": {
|
||||
|
@ -173,5 +174,4 @@ class SonarrAPI(object):
|
|||
}
|
||||
}
|
||||
)
|
||||
|
||||
self.dbmanager.write_points(influx_payload)
|
||||
|
|
|
@ -4,418 +4,246 @@ from logging import getLogger
|
|||
|
||||
logger = getLogger('temp')
|
||||
# Check for python3.6 or newer to resolve erroneous typing.NamedTuple issues
|
||||
if version_info < (3, 6):
|
||||
logger.error('Varken requires python3.6 or newer. You are on python%s.%s - Exiting...',
|
||||
version_info.major, version_info.minor)
|
||||
if version_info < (3, 6, 2):
|
||||
logger.error('Varken requires python3.6.2 or newer. You are on python%s.%s.%s - Exiting...',
|
||||
version_info.major, version_info.minor, version_info.micro)
|
||||
exit(1)
|
||||
|
||||
|
||||
class Queue(NamedTuple):
|
||||
movie: dict = None
|
||||
series: dict = None
|
||||
episode: dict = None
|
||||
quality: dict = None
|
||||
size: float = None
|
||||
title: str = None
|
||||
sizeleft: float = None
|
||||
timeleft: str = None
|
||||
estimatedCompletionTime: str = None
|
||||
status: str = None
|
||||
trackedDownloadStatus: str = None
|
||||
statusMessages: list = None
|
||||
downloadId: str = None
|
||||
protocol: str = None
|
||||
id: int = None
|
||||
# Server Structures
|
||||
class InfluxServer(NamedTuple):
|
||||
password: str = 'root'
|
||||
port: int = 8086
|
||||
url: str = 'localhost'
|
||||
username: str = 'root'
|
||||
|
||||
|
||||
class SonarrServer(NamedTuple):
|
||||
id: int = None
|
||||
url: str = None
|
||||
api_key: str = None
|
||||
verify_ssl: bool = False
|
||||
missing_days: int = 0
|
||||
missing_days_run_seconds: int = 30
|
||||
future_days: int = 0
|
||||
future_days_run_seconds: int = 30
|
||||
id: int = None
|
||||
missing_days: int = 0
|
||||
missing_days_run_seconds: int = 30
|
||||
queue: bool = False
|
||||
queue_run_seconds: int = 30
|
||||
url: str = None
|
||||
verify_ssl: bool = False
|
||||
|
||||
|
||||
class RadarrServer(NamedTuple):
|
||||
id: int = None
|
||||
url: str = None
|
||||
api_key: str = None
|
||||
verify_ssl: bool = False
|
||||
queue: bool = False
|
||||
queue_run_seconds: int = 30
|
||||
get_missing: bool = False
|
||||
get_missing_run_seconds: int = 30
|
||||
id: int = None
|
||||
queue: bool = False
|
||||
queue_run_seconds: int = 30
|
||||
url: str = None
|
||||
verify_ssl: bool = False
|
||||
|
||||
|
||||
class OmbiServer(NamedTuple):
|
||||
id: int = None
|
||||
url: str = None
|
||||
api_key: str = None
|
||||
verify_ssl: bool = False
|
||||
request_type_counts: bool = False
|
||||
request_type_run_seconds: int = 30
|
||||
id: int = None
|
||||
issue_status_counts: bool = False
|
||||
issue_status_run_seconds: int = 30
|
||||
request_total_counts: bool = False
|
||||
request_total_run_seconds: int = 30
|
||||
request_type_counts: bool = False
|
||||
request_type_run_seconds: int = 30
|
||||
url: str = None
|
||||
verify_ssl: bool = False
|
||||
|
||||
|
||||
class TautulliServer(NamedTuple):
|
||||
id: int = None
|
||||
url: str = None
|
||||
fallback_ip: str = None
|
||||
api_key: str = None
|
||||
verify_ssl: bool = None
|
||||
fallback_ip: str = None
|
||||
get_activity: bool = False
|
||||
get_activity_run_seconds: int = 30
|
||||
get_stats: bool = False
|
||||
get_stats_run_seconds: int = 30
|
||||
|
||||
|
||||
class InfluxServer(NamedTuple):
|
||||
url: str = 'localhost'
|
||||
port: int = 8086
|
||||
username: str = 'root'
|
||||
password: str = 'root'
|
||||
id: int = None
|
||||
url: str = None
|
||||
verify_ssl: bool = None
|
||||
|
||||
|
||||
class SickChillServer(NamedTuple):
|
||||
id: int = None
|
||||
url: str = None
|
||||
api_key: str = None
|
||||
verify_ssl: bool = False
|
||||
get_missing: bool = False
|
||||
get_missing_run_seconds: int = 30
|
||||
id: int = None
|
||||
url: str = None
|
||||
verify_ssl: bool = False
|
||||
|
||||
|
||||
class CiscoASAFirewall(NamedTuple):
|
||||
get_bandwidth_run_seconds: int = 30
|
||||
id: int = None
|
||||
outside_interface: str = None
|
||||
password: str = 'cisco'
|
||||
url: str = '192.168.1.1'
|
||||
username: str = 'cisco'
|
||||
password: str = 'cisco'
|
||||
outside_interface: str = None
|
||||
verify_ssl: bool = False
|
||||
get_bandwidth_run_seconds: int = 30
|
||||
|
||||
|
||||
# Shared
|
||||
class Queue(NamedTuple):
|
||||
downloadId: str = None
|
||||
episode: dict = None
|
||||
estimatedCompletionTime: str = None
|
||||
id: int = None
|
||||
movie: dict = None
|
||||
protocol: str = None
|
||||
quality: dict = None
|
||||
series: dict = None
|
||||
size: float = None
|
||||
sizeleft: float = None
|
||||
status: str = None
|
||||
statusMessages: list = None
|
||||
timeleft: str = None
|
||||
title: str = None
|
||||
trackedDownloadStatus: str = None
|
||||
|
||||
|
||||
# Ombi Structures
|
||||
class OmbiRequestCounts(NamedTuple):
|
||||
pending: int = 0
|
||||
approved: int = 0
|
||||
available: int = 0
|
||||
pending: int = 0
|
||||
|
||||
|
||||
class TautulliStream(NamedTuple):
|
||||
rating: str = None
|
||||
transcode_width: str = None
|
||||
labels: list = None
|
||||
stream_bitrate: str = None
|
||||
bandwidth: str = None
|
||||
optimized_version: int = None
|
||||
video_language: str = None
|
||||
parent_rating_key: str = None
|
||||
rating_key: str = None
|
||||
platform_version: str = None
|
||||
transcode_hw_decoding: int = None
|
||||
thumb: str = None
|
||||
title: str = None
|
||||
video_codec_level: str = None
|
||||
tagline: str = None
|
||||
last_viewed_at: str = None
|
||||
audio_sample_rate: str = None
|
||||
user_rating: str = None
|
||||
platform: str = None
|
||||
collections: list = None
|
||||
location: str = None
|
||||
transcode_container: str = None
|
||||
audio_channel_layout: str = None
|
||||
local: str = None
|
||||
stream_subtitle_format: str = None
|
||||
stream_video_ref_frames: str = None
|
||||
transcode_hw_encode_title: str = None
|
||||
stream_container_decision: str = None
|
||||
audience_rating: str = None
|
||||
full_title: str = None
|
||||
ip_address: str = None
|
||||
subtitles: int = None
|
||||
stream_subtitle_language: str = None
|
||||
channel_stream: int = None
|
||||
video_bitrate: str = None
|
||||
is_allow_sync: int = None
|
||||
stream_video_bitrate: str = None
|
||||
summary: str = None
|
||||
stream_audio_decision: str = None
|
||||
aspect_ratio: str = None
|
||||
audio_bitrate_mode: str = None
|
||||
transcode_hw_decode_title: str = None
|
||||
stream_audio_channel_layout: str = None
|
||||
deleted_user: int = None
|
||||
library_name: str = None
|
||||
art: str = None
|
||||
stream_video_resolution: str = None
|
||||
video_profile: str = None
|
||||
sort_title: str = None
|
||||
stream_video_codec_level: str = None
|
||||
stream_video_height: str = None
|
||||
year: str = None
|
||||
stream_duration: str = None
|
||||
stream_audio_channels: str = None
|
||||
video_language_code: str = None
|
||||
transcode_key: str = None
|
||||
transcode_throttled: int = None
|
||||
container: str = None
|
||||
stream_audio_bitrate: str = None
|
||||
user: str = None
|
||||
selected: int = None
|
||||
product_version: str = None
|
||||
subtitle_location: str = None
|
||||
transcode_hw_requested: int = None
|
||||
video_height: str = None
|
||||
state: str = None
|
||||
is_restricted: int = None
|
||||
email: str = None
|
||||
stream_container: str = None
|
||||
transcode_speed: str = None
|
||||
video_bit_depth: str = None
|
||||
stream_audio_sample_rate: str = None
|
||||
grandparent_title: str = None
|
||||
studio: str = None
|
||||
transcode_decision: str = None
|
||||
video_width: str = None
|
||||
bitrate: str = None
|
||||
machine_id: str = None
|
||||
originally_available_at: str = None
|
||||
video_frame_rate: str = None
|
||||
synced_version_profile: str = None
|
||||
friendly_name: str = None
|
||||
audio_profile: str = None
|
||||
optimized_version_title: str = None
|
||||
platform_name: str = None
|
||||
stream_video_language: str = None
|
||||
keep_history: int = None
|
||||
stream_audio_codec: str = None
|
||||
stream_video_codec: str = None
|
||||
grandparent_thumb: str = None
|
||||
synced_version: int = None
|
||||
transcode_hw_decode: str = None
|
||||
user_thumb: str = None
|
||||
stream_video_width: str = None
|
||||
height: str = None
|
||||
stream_subtitle_decision: str = None
|
||||
audio_codec: str = None
|
||||
parent_title: str = None
|
||||
guid: str = None
|
||||
audio_language_code: str = None
|
||||
transcode_video_codec: str = None
|
||||
transcode_audio_codec: str = None
|
||||
stream_video_decision: str = None
|
||||
user_id: int = None
|
||||
transcode_height: str = None
|
||||
transcode_hw_full_pipeline: int = None
|
||||
throttled: str = None
|
||||
quality_profile: str = None
|
||||
width: str = None
|
||||
live: int = None
|
||||
stream_subtitle_forced: int = None
|
||||
media_type: str = None
|
||||
video_resolution: str = None
|
||||
stream_subtitle_location: str = None
|
||||
do_notify: int = None
|
||||
video_ref_frames: str = None
|
||||
stream_subtitle_language_code: str = None
|
||||
audio_channels: str = None
|
||||
stream_audio_language_code: str = None
|
||||
optimized_version_profile: str = None
|
||||
relay: int = None
|
||||
duration: str = None
|
||||
rating_image: str = None
|
||||
is_home_user: int = None
|
||||
is_admin: int = None
|
||||
ip_address_public: str = None
|
||||
allow_guest: int = None
|
||||
transcode_audio_channels: str = None
|
||||
stream_audio_channel_layout_: str = None
|
||||
media_index: str = None
|
||||
stream_video_framerate: str = None
|
||||
transcode_hw_encode: str = None
|
||||
grandparent_rating_key: str = None
|
||||
original_title: str = None
|
||||
added_at: str = None
|
||||
banner: str = None
|
||||
bif_thumb: str = None
|
||||
parent_media_index: str = None
|
||||
live_uuid: str = None
|
||||
audio_language: str = None
|
||||
stream_audio_bitrate_mode: str = None
|
||||
username: str = None
|
||||
subtitle_decision: str = None
|
||||
children_count: str = None
|
||||
updated_at: str = None
|
||||
player: str = None
|
||||
subtitle_format: str = None
|
||||
file: str = None
|
||||
file_size: str = None
|
||||
session_key: str = None
|
||||
id: str = None
|
||||
subtitle_container: str = None
|
||||
genres: list = None
|
||||
stream_video_language_code: str = None
|
||||
indexes: int = None
|
||||
video_decision: str = None
|
||||
stream_audio_language: str = None
|
||||
writers: list = None
|
||||
actors: list = None
|
||||
progress_percent: str = None
|
||||
audio_decision: str = None
|
||||
subtitle_forced: int = None
|
||||
profile: str = None
|
||||
product: str = None
|
||||
view_offset: str = None
|
||||
type: str = None
|
||||
audience_rating_image: str = None
|
||||
audio_bitrate: str = None
|
||||
section_id: str = None
|
||||
stream_subtitle_codec: str = None
|
||||
subtitle_codec: str = None
|
||||
video_codec: str = None
|
||||
device: str = None
|
||||
stream_video_bit_depth: str = None
|
||||
video_framerate: str = None
|
||||
transcode_hw_encoding: int = None
|
||||
transcode_protocol: str = None
|
||||
shared_libraries: list = None
|
||||
stream_aspect_ratio: str = None
|
||||
content_rating: str = None
|
||||
session_id: str = None
|
||||
directors: list = None
|
||||
parent_thumb: str = None
|
||||
subtitle_language_code: str = None
|
||||
transcode_progress: int = None
|
||||
subtitle_language: str = None
|
||||
stream_subtitle_container: str = None
|
||||
sub_type: str = None
|
||||
extra_type: str = None
|
||||
|
||||
|
||||
class TVShow(NamedTuple):
|
||||
seriesId: int = None
|
||||
episodeFileId: int = None
|
||||
seasonNumber: int = None
|
||||
episodeNumber: int = None
|
||||
title: str = None
|
||||
airDate: str = None
|
||||
airDateUtc: str = None
|
||||
overview: str = None
|
||||
episodeFile: dict = None
|
||||
hasFile: bool = None
|
||||
monitored: bool = None
|
||||
unverifiedSceneNumbering: bool = None
|
||||
absoluteEpisodeNumber: int = None
|
||||
sceneAbsoluteEpisodeNumber: int = None
|
||||
sceneEpisodeNumber: int = None
|
||||
sceneSeasonNumber: int = None
|
||||
series: dict = None
|
||||
id: int = None
|
||||
|
||||
|
||||
class Movie(NamedTuple):
|
||||
title: str = None
|
||||
alternativeTitles: list = None
|
||||
secondaryYearSourceId: int = None
|
||||
sortTitle: str = None
|
||||
sizeOnDisk: int = None
|
||||
status: str = None
|
||||
overview: str = None
|
||||
inCinemas: str = None
|
||||
images: list = None
|
||||
downloaded: bool = None
|
||||
year: int = None
|
||||
secondaryYear: str = None
|
||||
hasFile: bool = None
|
||||
youTubeTrailerId: str = None
|
||||
studio: str = None
|
||||
path: str = None
|
||||
profileId: int = None
|
||||
pathState: str = None
|
||||
monitored: bool = None
|
||||
minimumAvailability: str = None
|
||||
isAvailable: bool = None
|
||||
folderName: str = None
|
||||
runtime: int = None
|
||||
lastInfoSync: str = None
|
||||
cleanTitle: str = None
|
||||
imdbId: str = None
|
||||
tmdbId: int = None
|
||||
titleSlug: str = None
|
||||
genres: list = None
|
||||
tags: list = None
|
||||
added: str = None
|
||||
ratings: dict = None
|
||||
movieFile: dict = None
|
||||
qualityProfileId: int = None
|
||||
physicalRelease: str = None
|
||||
physicalReleaseNote: str = None
|
||||
website: str = None
|
||||
id: int = None
|
||||
|
||||
|
||||
class OmbiMovieRequest(NamedTuple):
|
||||
theMovieDbId: int = None
|
||||
issueId: None = None
|
||||
issues: None = None
|
||||
subscribed: bool = None
|
||||
showSubscribe: bool = None
|
||||
rootPathOverride: int = None
|
||||
qualityOverride: int = None
|
||||
imdbId: str = None
|
||||
overview: str = None
|
||||
posterPath: str = None
|
||||
releaseDate: str = None
|
||||
digitalReleaseDate: None = None
|
||||
status: str = None
|
||||
background: str = None
|
||||
released: bool = None
|
||||
digitalRelease: bool = None
|
||||
title: str = None
|
||||
approved: bool = None
|
||||
markedAsApproved: str = None
|
||||
requestedDate: str = None
|
||||
available: bool = None
|
||||
markedAsAvailable: None = None
|
||||
requestedUserId: str = None
|
||||
denied: bool = None
|
||||
markedAsDenied: str = None
|
||||
deniedReason: None = None
|
||||
requestType: int = None
|
||||
requestedUser: dict = None
|
||||
canApprove: bool = None
|
||||
id: int = None
|
||||
class OmbiIssuesCounts(NamedTuple):
|
||||
inProgress: int = 0
|
||||
pending: int = 0
|
||||
resolved: int = 0
|
||||
|
||||
|
||||
class OmbiTVRequest(NamedTuple):
|
||||
tvDbId: int = None
|
||||
imdbId: str = None
|
||||
qualityOverride: None = None
|
||||
rootFolder: None = None
|
||||
overview: str = None
|
||||
title: str = None
|
||||
posterPath: str = None
|
||||
background: str = None
|
||||
releaseDate: str = None
|
||||
status: str = None
|
||||
totalSeasons: int = None
|
||||
childRequests: list = None
|
||||
denied: bool = None
|
||||
deniedReason: None = None
|
||||
id: int = None
|
||||
imdbId: str = None
|
||||
markedAsDenied: str = None
|
||||
overview: str = None
|
||||
posterPath: str = None
|
||||
qualityOverride: None = None
|
||||
releaseDate: str = None
|
||||
rootFolder: None = None
|
||||
status: str = None
|
||||
title: str = None
|
||||
totalSeasons: int = None
|
||||
tvDbId: int = None
|
||||
|
||||
|
||||
class OmbiMovieRequest(NamedTuple):
|
||||
approved: bool = None
|
||||
available: bool = None
|
||||
background: str = None
|
||||
canApprove: bool = None
|
||||
denied: bool = None
|
||||
deniedReason: None = None
|
||||
digitalRelease: bool = None
|
||||
digitalReleaseDate: None = None
|
||||
id: int = None
|
||||
imdbId: str = None
|
||||
issueId: None = None
|
||||
issues: None = None
|
||||
markedAsApproved: str = None
|
||||
markedAsAvailable: None = None
|
||||
markedAsDenied: str = None
|
||||
overview: str = None
|
||||
posterPath: str = None
|
||||
qualityOverride: int = None
|
||||
released: bool = None
|
||||
releaseDate: str = None
|
||||
requestedDate: str = None
|
||||
requestedUser: dict = None
|
||||
requestedUserId: str = None
|
||||
requestType: int = None
|
||||
rootPathOverride: int = None
|
||||
showSubscribe: bool = None
|
||||
status: str = None
|
||||
subscribed: bool = None
|
||||
theMovieDbId: int = None
|
||||
title: str = None
|
||||
|
||||
|
||||
# Sonarr
|
||||
class SonarrTVShow(NamedTuple):
|
||||
absoluteEpisodeNumber: int = None
|
||||
airDate: str = None
|
||||
airDateUtc: str = None
|
||||
episodeFile: dict = None
|
||||
episodeFileId: int = None
|
||||
episodeNumber: int = None
|
||||
hasFile: bool = None
|
||||
id: int = None
|
||||
lastSearchTime: str = None
|
||||
monitored: bool = None
|
||||
overview: str = None
|
||||
sceneAbsoluteEpisodeNumber: int = None
|
||||
sceneEpisodeNumber: int = None
|
||||
sceneSeasonNumber: int = None
|
||||
seasonNumber: int = None
|
||||
series: dict = None
|
||||
seriesId: int = None
|
||||
title: str = None
|
||||
unverifiedSceneNumbering: bool = None
|
||||
|
||||
|
||||
# Radarr
|
||||
class RadarrMovie(NamedTuple):
|
||||
added: str = None
|
||||
addOptions: str = None
|
||||
alternativeTitles: list = None
|
||||
certification: str = None
|
||||
cleanTitle: str = None
|
||||
downloaded: bool = None
|
||||
folderName: str = None
|
||||
genres: list = None
|
||||
hasFile: bool = None
|
||||
id: int = None
|
||||
images: list = None
|
||||
imdbId: str = None
|
||||
inCinemas: str = None
|
||||
isAvailable: bool = None
|
||||
lastInfoSync: str = None
|
||||
minimumAvailability: str = None
|
||||
monitored: bool = None
|
||||
movieFile: dict = None
|
||||
overview: str = None
|
||||
path: str = None
|
||||
pathState: str = None
|
||||
physicalRelease: str = None
|
||||
physicalReleaseNote: str = None
|
||||
profileId: int = None
|
||||
qualityProfileId: int = None
|
||||
ratings: dict = None
|
||||
runtime: int = None
|
||||
secondaryYear: str = None
|
||||
secondaryYearSourceId: int = None
|
||||
sizeOnDisk: int = None
|
||||
sortTitle: str = None
|
||||
status: str = None
|
||||
studio: str = None
|
||||
tags: list = None
|
||||
title: str = None
|
||||
titleSlug: str = None
|
||||
tmdbId: int = None
|
||||
website: str = None
|
||||
year: int = None
|
||||
youTubeTrailerId: str = None
|
||||
|
||||
|
||||
# Sickchill
|
||||
class SickChillTVShow(NamedTuple):
|
||||
airdate: str = None
|
||||
airs: str = None
|
||||
episode: int = None
|
||||
ep_name: str = None
|
||||
ep_plot: str = None
|
||||
episode: int = None
|
||||
indexerid: int = None
|
||||
network: str = None
|
||||
paused: int = None
|
||||
|
@ -425,3 +253,198 @@ class SickChillTVShow(NamedTuple):
|
|||
show_status: str = None
|
||||
tvdbid: int = None
|
||||
weekday: int = None
|
||||
|
||||
|
||||
# Tautulli
|
||||
class TautulliStream(NamedTuple):
|
||||
actors: list = None
|
||||
added_at: str = None
|
||||
allow_guest: int = None
|
||||
art: str = None
|
||||
aspect_ratio: str = None
|
||||
audience_rating: str = None
|
||||
audience_rating_image: str = None
|
||||
audio_bitrate: str = None
|
||||
audio_bitrate_mode: str = None
|
||||
audio_channels: str = None
|
||||
audio_channel_layout: str = None
|
||||
audio_codec: str = None
|
||||
audio_decision: str = None
|
||||
audio_language: str = None
|
||||
audio_language_code: str = None
|
||||
audio_profile: str = None
|
||||
audio_sample_rate: str = None
|
||||
bandwidth: str = None
|
||||
banner: str = None
|
||||
bif_thumb: str = None
|
||||
bitrate: str = None
|
||||
channel_icon: str = None
|
||||
channel_stream: int = None
|
||||
channel_title: str = None
|
||||
children_count: str = None
|
||||
collections: list = None
|
||||
container: str = None
|
||||
content_rating: str = None
|
||||
deleted_user: int = None
|
||||
device: str = None
|
||||
directors: list = None
|
||||
do_notify: int = None
|
||||
duration: str = None
|
||||
email: str = None
|
||||
extra_type: str = None
|
||||
file: str = None
|
||||
file_size: str = None
|
||||
friendly_name: str = None
|
||||
full_title: str = None
|
||||
genres: list = None
|
||||
grandparent_rating_key: str = None
|
||||
grandparent_thumb: str = None
|
||||
grandparent_title: str = None
|
||||
guid: str = None
|
||||
height: str = None
|
||||
id: str = None
|
||||
indexes: int = None
|
||||
ip_address: str = None
|
||||
ip_address_public: str = None
|
||||
is_admin: int = None
|
||||
is_allow_sync: int = None
|
||||
is_home_user: int = None
|
||||
is_restricted: int = None
|
||||
keep_history: int = None
|
||||
labels: list = None
|
||||
last_viewed_at: str = None
|
||||
library_name: str = None
|
||||
live: int = None
|
||||
live_uuid: str = None
|
||||
local: str = None
|
||||
location: str = None
|
||||
machine_id: str = None
|
||||
media_index: str = None
|
||||
media_type: str = None
|
||||
optimized_version: int = None
|
||||
optimized_version_profile: str = None
|
||||
optimized_version_title: str = None
|
||||
originally_available_at: str = None
|
||||
original_title: str = None
|
||||
parent_media_index: str = None
|
||||
parent_rating_key: str = None
|
||||
parent_thumb: str = None
|
||||
parent_title: str = None
|
||||
platform: str = None
|
||||
platform_name: str = None
|
||||
platform_version: str = None
|
||||
player: str = None
|
||||
product: str = None
|
||||
product_version: str = None
|
||||
profile: str = None
|
||||
progress_percent: str = None
|
||||
quality_profile: str = None
|
||||
rating: str = None
|
||||
rating_image: str = None
|
||||
rating_key: str = None
|
||||
relay: int = None
|
||||
section_id: str = None
|
||||
selected: int = None
|
||||
session_id: str = None
|
||||
session_key: str = None
|
||||
shared_libraries: list = None
|
||||
sort_title: str = None
|
||||
state: str = None
|
||||
stream_aspect_ratio: str = None
|
||||
stream_audio_bitrate: str = None
|
||||
stream_audio_bitrate_mode: str = None
|
||||
stream_audio_channels: str = None
|
||||
stream_audio_channel_layout: str = None
|
||||
stream_audio_channel_layout_: str = None
|
||||
stream_audio_codec: str = None
|
||||
stream_audio_decision: str = None
|
||||
stream_audio_language: str = None
|
||||
stream_audio_language_code: str = None
|
||||
stream_audio_sample_rate: str = None
|
||||
stream_bitrate: str = None
|
||||
stream_container: str = None
|
||||
stream_container_decision: str = None
|
||||
stream_duration: str = None
|
||||
stream_subtitle_codec: str = None
|
||||
stream_subtitle_container: str = None
|
||||
stream_subtitle_decision: str = None
|
||||
stream_subtitle_forced: int = None
|
||||
stream_subtitle_format: str = None
|
||||
stream_subtitle_language: str = None
|
||||
stream_subtitle_language_code: str = None
|
||||
stream_subtitle_location: str = None
|
||||
stream_video_bitrate: str = None
|
||||
stream_video_bit_depth: str = None
|
||||
stream_video_codec: str = None
|
||||
stream_video_codec_level: str = None
|
||||
stream_video_decision: str = None
|
||||
stream_video_framerate: str = None
|
||||
stream_video_height: str = None
|
||||
stream_video_language: str = None
|
||||
stream_video_language_code: str = None
|
||||
stream_video_ref_frames: str = None
|
||||
stream_video_resolution: str = None
|
||||
stream_video_width: str = None
|
||||
studio: str = None
|
||||
subtitles: int = None
|
||||
subtitle_codec: str = None
|
||||
subtitle_container: str = None
|
||||
subtitle_decision: str = None
|
||||
subtitle_forced: int = None
|
||||
subtitle_format: str = None
|
||||
subtitle_language: str = None
|
||||
subtitle_language_code: str = None
|
||||
subtitle_location: str = None
|
||||
sub_type: str = None
|
||||
summary: str = None
|
||||
synced_version: int = None
|
||||
synced_version_profile: str = None
|
||||
tagline: str = None
|
||||
throttled: str = None
|
||||
thumb: str = None
|
||||
title: str = None
|
||||
transcode_audio_channels: str = None
|
||||
transcode_audio_codec: str = None
|
||||
transcode_container: str = None
|
||||
transcode_decision: str = None
|
||||
transcode_height: str = None
|
||||
transcode_hw_decode: str = None
|
||||
transcode_hw_decode_title: str = None
|
||||
transcode_hw_decoding: int = None
|
||||
transcode_hw_encode: str = None
|
||||
transcode_hw_encode_title: str = None
|
||||
transcode_hw_encoding: int = None
|
||||
transcode_hw_full_pipeline: int = None
|
||||
transcode_hw_requested: int = None
|
||||
transcode_key: str = None
|
||||
transcode_progress: int = None
|
||||
transcode_protocol: str = None
|
||||
transcode_speed: str = None
|
||||
transcode_throttled: int = None
|
||||
transcode_video_codec: str = None
|
||||
transcode_width: str = None
|
||||
type: str = None
|
||||
updated_at: str = None
|
||||
user: str = None
|
||||
username: str = None
|
||||
user_id: int = None
|
||||
user_rating: str = None
|
||||
user_thumb: str = None
|
||||
video_bitrate: str = None
|
||||
video_bit_depth: str = None
|
||||
video_codec: str = None
|
||||
video_codec_level: str = None
|
||||
video_decision: str = None
|
||||
video_framerate: str = None
|
||||
video_frame_rate: str = None
|
||||
video_height: str = None
|
||||
video_language: str = None
|
||||
video_language_code: str = None
|
||||
video_profile: str = None
|
||||
video_ref_frames: str = None
|
||||
video_resolution: str = None
|
||||
video_width: str = None
|
||||
view_offset: str = None
|
||||
width: str = None
|
||||
writers: list = None
|
||||
year: str = None
|
||||
|
|
|
@ -108,6 +108,8 @@ class TautulliAPI(object):
|
|||
"quality": quality,
|
||||
"video_decision": video_decision.title(),
|
||||
"transcode_decision": decision.title(),
|
||||
"transcode_hw_decoding": session.transcode_hw_decoding,
|
||||
"transcode_hw_encoding": session.transcode_hw_encoding,
|
||||
"media_type": session.media_type.title(),
|
||||
"audio_codec": session.audio_codec.upper(),
|
||||
"audio_profile": session.audio_profile.upper(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue