Add Overseerr Support (#210)
This commit is contained in:
parent
9498a83bc8
commit
73b2686ba0
5 changed files with 312 additions and 3 deletions
16
Varken.py
16
Varken.py
|
@ -14,6 +14,7 @@ from logging import getLogger, StreamHandler, Formatter, DEBUG
|
|||
# Needed to check version of python
|
||||
from varken import structures # noqa
|
||||
from varken.ombi import OmbiAPI
|
||||
from varken.overseerr import OverseerrAPI
|
||||
from varken.unifi import UniFiAPI
|
||||
from varken import VERSION, BRANCH, BUILD_DATE
|
||||
from varken.sonarr import SonarrAPI
|
||||
|
@ -156,6 +157,21 @@ if __name__ == "__main__":
|
|||
at_time = schedule.every(server.issue_status_run_seconds).seconds
|
||||
at_time.do(thread, OMBI.get_issue_counts).tag("ombi-{}-get_issue_counts".format(server.id))
|
||||
|
||||
if CONFIG.overseerr_enabled:
|
||||
for server in CONFIG.overseerr_servers:
|
||||
OVERSEER = OverseerrAPI(server, DBMANAGER)
|
||||
if server.get_request_total_counts:
|
||||
at_time = schedule.every(server.request_total_run_seconds).seconds
|
||||
at_time.do(thread, OVERSEER.get_total_requests).tag("overseerr-{}-get_total_requests".format(server.id))
|
||||
if server.get_request_status_counts:
|
||||
at_time = schedule.every(server.request_status_run_seconds).seconds
|
||||
at_time.do(thread, OVERSEER.get_request_status_counts).tag("overseerr-{}-get_request_status_counts"
|
||||
.format(server.id))
|
||||
if server.get_latest_requests:
|
||||
at_time = schedule.every(server.num_latest_requests_seconds).seconds
|
||||
at_time.do(thread, OVERSEER.get_latest_requests).tag("overseerr-{}-get_latest_requests"
|
||||
.format(server.id))
|
||||
|
||||
if CONFIG.sickchill_enabled:
|
||||
for server in CONFIG.sickchill_servers:
|
||||
SICKCHILL = SickChillAPI(server, DBMANAGER)
|
||||
|
|
|
@ -3,7 +3,8 @@ sonarr_server_ids = 1,2
|
|||
radarr_server_ids = 1,2
|
||||
lidarr_server_ids = false
|
||||
tautulli_server_ids = 1
|
||||
ombi_server_ids = 1
|
||||
ombi_server_ids = false
|
||||
overseerr_server_ids = 1
|
||||
sickchill_server_ids = false
|
||||
unifi_server_ids = false
|
||||
maxmind_license_key = xxxxxxxxxxxxxxxx
|
||||
|
@ -95,6 +96,19 @@ request_total_run_seconds = 300
|
|||
get_issue_status_counts = true
|
||||
issue_status_run_seconds = 300
|
||||
|
||||
[overseerr-1]
|
||||
url = overseerr.domain.tld
|
||||
apikey = xxxxxxxxxxxxxxxx
|
||||
ssl = false
|
||||
verify_ssl = false
|
||||
get_request_total_counts = true
|
||||
request_total_run_seconds = 300
|
||||
get_request_status_counts = true
|
||||
request_status_run_seconds = 300
|
||||
get_latest_requests = true
|
||||
num_latest_requests_to_fetch = 10
|
||||
num_latest_requests_seconds = 300
|
||||
|
||||
[sickchill-1]
|
||||
url = sickchill.domain.tld:8081
|
||||
apikey = xxxxxxxxxxxxxxxx
|
||||
|
|
|
@ -9,7 +9,7 @@ from configparser import ConfigParser, NoOptionError, NoSectionError
|
|||
from varken.varkenlogger import BlacklistFilter
|
||||
from varken.structures import SickChillServer, UniFiServer
|
||||
from varken.helpers import clean_sid_check, rfc1918_ip_check, boolcheck
|
||||
from varken.structures import SonarrServer, RadarrServer, OmbiServer, TautulliServer, InfluxServer
|
||||
from varken.structures import SonarrServer, RadarrServer, OmbiServer, OverseerrServer, TautulliServer, InfluxServer
|
||||
|
||||
|
||||
class INIParser(object):
|
||||
|
@ -17,7 +17,7 @@ class INIParser(object):
|
|||
self.config = None
|
||||
self.data_folder = data_folder
|
||||
self.filtered_strings = None
|
||||
self.services = ['sonarr', 'radarr', 'lidarr', 'ombi', 'tautulli', 'sickchill', 'unifi']
|
||||
self.services = ['sonarr', 'radarr', 'lidarr', 'ombi', 'overseerr', 'tautulli', 'sickchill', 'unifi']
|
||||
|
||||
self.logger = getLogger()
|
||||
self.influx_server = InfluxServer()
|
||||
|
@ -293,6 +293,38 @@ class INIParser(object):
|
|||
issue_status_counts=issue_status_counts,
|
||||
issue_status_run_seconds=issue_status_run_seconds)
|
||||
|
||||
if service == 'overseerr':
|
||||
get_latest_requests = boolcheck(env.get(
|
||||
f'VRKN_{envsection}_GET_LATEST_REQUESTS',
|
||||
self.config.get(section, 'get_latest_requests')))
|
||||
num_latest_requests_to_fetch = int(env.get(
|
||||
f'VRKN_{envsection}_NUM_LATEST_REQUESTS',
|
||||
self.config.getint(section, 'num_latest_requests_to_fetch')))
|
||||
num_latest_requests_seconds = int(env.get(
|
||||
f'VRKN_{envsection}_NUM_LATEST_REQUESTS_SECONDS',
|
||||
self.config.getint(section, 'num_latest_requests_seconds')))
|
||||
get_request_total_counts = boolcheck(env.get(
|
||||
f'VRKN_{envsection}_GET_REQUEST_TOTAL_COUNTS',
|
||||
self.config.get(section, 'get_request_total_counts')))
|
||||
request_total_run_seconds = int(env.get(
|
||||
f'VRKN_{envsection}_REQUEST_TOTAL_RUN_SECONDS',
|
||||
self.config.getint(section, 'request_total_run_seconds')))
|
||||
get_request_status_counts = boolcheck(env.get(
|
||||
f'VRKN_{envsection}_GET_REQUEST_STATUS_COUNTS',
|
||||
self.config.get(section, 'get_request_status_counts')))
|
||||
request_status_run_seconds = int(env.get(
|
||||
f'VRKN_{envsection}_REQUEST_STATUS_RUN_SECONDS',
|
||||
self.config.getint(section, 'request_status_run_seconds')))
|
||||
|
||||
server = OverseerrServer(id=server_id, url=scheme + url, api_key=apikey,
|
||||
verify_ssl=verify_ssl, get_latest_requests=get_latest_requests,
|
||||
num_latest_requests_to_fetch=num_latest_requests_to_fetch,
|
||||
num_latest_requests_seconds=num_latest_requests_seconds,
|
||||
get_request_total_counts=get_request_total_counts,
|
||||
request_total_run_seconds=request_total_run_seconds,
|
||||
get_request_status_counts=get_request_status_counts,
|
||||
request_status_run_seconds=request_status_run_seconds)
|
||||
|
||||
if service == 'sickchill':
|
||||
get_missing = boolcheck(env.get(f'VRKN_{envsection}_GET_MISSING',
|
||||
self.config.get(section, 'get_missing')))
|
||||
|
|
179
varken/overseerr.py
Normal file
179
varken/overseerr.py
Normal file
|
@ -0,0 +1,179 @@
|
|||
from logging import getLogger
|
||||
from requests import Session, Request
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from varken.helpers import connection_handler, hashit
|
||||
from varken.structures import OverseerrRequest, OverseerrRequestCounts
|
||||
|
||||
|
||||
class OverseerrAPI(object):
|
||||
def __init__(self, server, dbmanager):
|
||||
self.dbmanager = dbmanager
|
||||
self.server = server
|
||||
# Create session to reduce server web thread load, and globally define pageSize for all requests
|
||||
self.session = Session()
|
||||
self.session.headers = {'X-Api-Key': self.server.api_key}
|
||||
self.logger = getLogger()
|
||||
|
||||
def __repr__(self):
|
||||
return f"<overseerr-{self.server.id}>"
|
||||
|
||||
def get_total_requests(self):
|
||||
now = datetime.now(timezone.utc).astimezone().isoformat()
|
||||
endpoint = '/api/v1/request?take=200&filter=all&sort=added'
|
||||
|
||||
req = self.session.prepare_request(Request('GET', self.server.url + endpoint))
|
||||
get_req = connection_handler(self.session, req, self.server.verify_ssl) or []
|
||||
|
||||
if not any([get_req]):
|
||||
self.logger.error('No json replies. Discarding job')
|
||||
return
|
||||
|
||||
tv_requests = []
|
||||
movie_requests = []
|
||||
|
||||
for result in get_req['results']:
|
||||
if result['type'] == 'tv':
|
||||
try:
|
||||
tv_requests.append(OverseerrRequest(**result))
|
||||
except TypeError as e:
|
||||
self.logger.error('TypeError has occurred : %s while creating OverseerrRequest structure for show. '
|
||||
'data attempted is: %s', e, result)
|
||||
|
||||
if result['type'] == 'movie':
|
||||
try:
|
||||
movie_requests.append(OverseerrRequest(**result))
|
||||
except TypeError as e:
|
||||
self.logger.error('TypeError has occurred : %s while creating OverseerrRequest \
|
||||
structure for movie. '
|
||||
'data attempted is: %s', e, result)
|
||||
|
||||
if tv_requests:
|
||||
tv_request_count = len(tv_requests)
|
||||
|
||||
if movie_requests:
|
||||
movie_request_count = len(movie_requests)
|
||||
|
||||
influx_payload = [
|
||||
{
|
||||
"measurement": "Overseerr",
|
||||
"tags": {
|
||||
"type": "Request_Totals",
|
||||
"server": self.server.id
|
||||
},
|
||||
"time": now,
|
||||
"fields": {
|
||||
"total": movie_request_count + tv_request_count,
|
||||
"movies": movie_request_count,
|
||||
"tv": tv_request_count
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
if influx_payload:
|
||||
self.dbmanager.write_points(influx_payload)
|
||||
else:
|
||||
self.logger.debug("Empty dataset for overseerr module. Discarding...")
|
||||
|
||||
def get_request_status_counts(self):
|
||||
now = datetime.now(timezone.utc).astimezone().isoformat()
|
||||
endpoint = '/api/v1/request/count'
|
||||
|
||||
req = self.session.prepare_request(Request('GET', self.server.url + endpoint))
|
||||
get_req = connection_handler(self.session, req, self.server.verify_ssl)
|
||||
|
||||
if not get_req:
|
||||
return
|
||||
|
||||
requests = OverseerrRequestCounts(**get_req)
|
||||
influx_payload = [
|
||||
{
|
||||
"measurement": "Overseerr",
|
||||
"tags": {
|
||||
"type": "Request_Counts"
|
||||
},
|
||||
"time": now,
|
||||
"fields": {
|
||||
"pending": requests.pending,
|
||||
"approved": requests.approved,
|
||||
"processing": requests.processing,
|
||||
"available": requests.available
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
self.dbmanager.write_points(influx_payload)
|
||||
|
||||
def get_latest_requests(self):
|
||||
now = datetime.now(timezone.utc).astimezone().isoformat()
|
||||
endpoint = '/api/v1/request?take=' + str(self.server.num_latest_requests_to_fetch) + '&filter=all&sort=added'
|
||||
movie_endpoint = '/api/v1/movie/'
|
||||
tv_endpoint = '/api/v1/tv/'
|
||||
|
||||
# GET THE LATEST n REQUESTS
|
||||
req = self.session.prepare_request(Request('GET', self.server.url + endpoint))
|
||||
get_latest_req = connection_handler(self.session, req, self.server.verify_ssl)
|
||||
|
||||
# RETURN NOTHING IF NO RESULTS
|
||||
if not get_latest_req:
|
||||
return
|
||||
|
||||
influx_payload = []
|
||||
|
||||
# Request Type: Movie = 1, TV Show = 0
|
||||
for result in get_latest_req['results']:
|
||||
if result['type'] == 'tv':
|
||||
req = self.session.prepare_request(Request('GET',
|
||||
self.server.url +
|
||||
tv_endpoint +
|
||||
str(result['media']['tmdbId'])))
|
||||
get_tv_req = connection_handler(self.session, req, self.server.verify_ssl)
|
||||
hash_id = hashit(f'{get_tv_req["id"]}{get_tv_req["name"]}')
|
||||
|
||||
influx_payload.append(
|
||||
{
|
||||
"measurement": "Overseerr",
|
||||
"tags": {
|
||||
"type": "Requests",
|
||||
"server": self.server.id,
|
||||
"request_type": 0,
|
||||
"status": get_tv_req['mediaInfo']['status'],
|
||||
"title": get_tv_req['name'],
|
||||
"requested_user": get_tv_req['mediaInfo']['requests'][0]['requestedBy']['plexUsername'],
|
||||
"requested_date": get_tv_req['mediaInfo']['requests'][0]['requestedBy']['createdAt']
|
||||
},
|
||||
"time": now,
|
||||
"fields": {
|
||||
"hash": hash_id
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if result['type'] == 'movie':
|
||||
req = self.session.prepare_request(Request('GET',
|
||||
self.server.url +
|
||||
movie_endpoint +
|
||||
str(result['media']['tmdbId'])))
|
||||
get_movie_req = connection_handler(self.session, req, self.server.verify_ssl)
|
||||
hash_id = hashit(f'{get_movie_req["id"]}{get_movie_req["title"]}')
|
||||
|
||||
influx_payload.append(
|
||||
{
|
||||
"measurement": "Overseerr",
|
||||
"tags": {
|
||||
"type": "Requests",
|
||||
"server": self.server.id,
|
||||
"request_type": 1,
|
||||
"status": get_movie_req['mediaInfo']['status'],
|
||||
"title": get_movie_req['title'],
|
||||
"requested_user": get_movie_req['mediaInfo']['requests'][0]['requestedBy']['plexUsername'],
|
||||
"requested_date": get_movie_req['mediaInfo']['requests'][0]['requestedBy']['createdAt']
|
||||
},
|
||||
"time": now,
|
||||
"fields": {
|
||||
"hash": hash_id
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
self.dbmanager.write_points(influx_payload)
|
|
@ -57,6 +57,20 @@ class OmbiServer(NamedTuple):
|
|||
verify_ssl: bool = False
|
||||
|
||||
|
||||
class OverseerrServer(NamedTuple):
|
||||
api_key: str = None
|
||||
id: int = None
|
||||
url: str = None
|
||||
verify_ssl: bool = False
|
||||
get_request_total_counts: bool = False
|
||||
request_total_run_seconds: int = 30
|
||||
get_request_status_counts: bool = False
|
||||
request_status_run_seconds: int = 30
|
||||
get_latest_requests: bool = False
|
||||
num_latest_requests_to_fetch: int = 10
|
||||
num_latest_requests_seconds: int = 30
|
||||
|
||||
|
||||
class TautulliServer(NamedTuple):
|
||||
api_key: str = None
|
||||
fallback_ip: str = None
|
||||
|
@ -173,6 +187,60 @@ class OmbiMovieRequest(NamedTuple):
|
|||
requestStatus: str = None
|
||||
|
||||
|
||||
# Overseerr
|
||||
class OverseerrRequest(NamedTuple):
|
||||
id: int = None
|
||||
status: int = None
|
||||
createdAt: str = None
|
||||
updatedAt: str = None
|
||||
type: str = None
|
||||
is4k: bool = None
|
||||
serverId: int = None
|
||||
profileId: int = None
|
||||
rootFolder: str = None
|
||||
languageProfileId: int = None
|
||||
tags: list = None
|
||||
media: dict = None
|
||||
seasons: list = None
|
||||
modifiedBy: dict = None
|
||||
requestedBy: dict = None
|
||||
seasonCount: int = None
|
||||
|
||||
|
||||
class OverseerrRequestCounts(NamedTuple):
|
||||
pending: int = None
|
||||
approved: int = None
|
||||
processing: int = None
|
||||
available: int = None
|
||||
|
||||
|
||||
# Overseerr
|
||||
class OverseerrRequest(NamedTuple):
|
||||
id: int = None
|
||||
status: int = None
|
||||
createdAt: str = None
|
||||
updatedAt: str = None
|
||||
type: str = None
|
||||
is4k: bool = None
|
||||
serverId: int = None
|
||||
profileId: int = None
|
||||
rootFolder: str = None
|
||||
languageProfileId: int = None
|
||||
tags: list = None
|
||||
media: dict = None
|
||||
seasons: list = None
|
||||
modifiedBy: dict = None
|
||||
requestedBy: dict = None
|
||||
seasonCount: int = None
|
||||
|
||||
|
||||
class OverseerrRequestCounts(NamedTuple):
|
||||
pending: int = None
|
||||
approved: int = None
|
||||
processing: int = None
|
||||
available: int = None
|
||||
|
||||
|
||||
# Sonarr
|
||||
class SonarrTVShow(NamedTuple):
|
||||
added: str = None
|
||||
|
|
Loading…
Reference in a new issue