updated to support Radarr and Sonarr V3 Api

This commit is contained in:
Robin 2021-09-17 22:55:02 +00:00
parent c6b8dde29a
commit 57028cd26c
3 changed files with 198 additions and 70 deletions

View file

@ -2,7 +2,7 @@ from logging import getLogger
from requests import Session, Request
from datetime import datetime, timezone
from varken.structures import RadarrMovie, Queue
from varken.structures import QueuePages, RadarrMovie, RadarrQueue
from varken.helpers import hashit, connection_handler
@ -18,8 +18,19 @@ class RadarrAPI(object):
def __repr__(self):
return f"<radarr-{self.server.id}>"
def get_movie(self,id):
endpoint = '/api/v3/movie/'
req = self.session.prepare_request(Request('GET', self.server.url + endpoint + str(id)))
get = connection_handler(self.session, req, self.server.verify_ssl)
if not get:
return
return RadarrMovie(**get)
def get_missing(self):
endpoint = '/api/movie'
endpoint = '/api/v3/movie'
now = datetime.now(timezone.utc).astimezone().isoformat()
influx_payload = []
missing = []
@ -37,7 +48,7 @@ class RadarrAPI(object):
return
for movie in movies:
if movie.monitored and not movie.downloaded:
if movie.monitored and not movie.hasFile:
if movie.isAvailable:
ma = 0
else:
@ -69,32 +80,45 @@ class RadarrAPI(object):
self.dbmanager.write_points(influx_payload)
def get_queue(self):
endpoint = '/api/queue'
endpoint = '/api/v3/queue'
now = datetime.now(timezone.utc).astimezone().isoformat()
influx_payload = []
pageSize = 250
params = {'pageSize': pageSize}
queueResponse = []
queue = []
req = self.session.prepare_request(Request('GET', self.server.url + endpoint))
req = self.session.prepare_request(Request('GET', self.server.url + endpoint,params=params))
get = connection_handler(self.session, req, self.server.verify_ssl)
if not get:
return
response = QueuePages(**get)
queueResponse.extend(response.records)
for movie in get:
try:
movie['movie'] = RadarrMovie(**movie['movie'])
except TypeError as e:
self.logger.error('TypeError has occurred : %s while creating RadarrMovie structure', e)
while response.totalRecords > response.page * response.pageSize:
page = response.page + 1
params = {'pageSize': pageSize, 'page': page}
req = self.session.prepare_request(Request('GET', self.server.url + endpoint,params=params))
get = connection_handler(self.session, req, self.server.verify_ssl)
if not get:
return
try:
download_queue = [Queue(**movie) for movie in get]
except TypeError as e:
self.logger.error('TypeError has occurred : %s while creating Queue structure', e)
response = QueuePages(**get)
queueResponse.extend(response.records)
download_queue = []
for queueItem in queueResponse:
try:
download_queue.append(RadarrQueue(**queueItem))
except TypeError as e:
self.logger.error('TypeError has occurred : %s while creating RadarrQueue structure', e)
return
if not download_queue:
return
for queue_item in download_queue:
movie = queue_item.movie
movie = self.get_movie(queue_item.movieId)
name = f'{movie.title} ({movie.year})'

View file

@ -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, SonarrTVShow
from varken.structures import SonarrEpisode, SonarrQueue, QueuePages, SonarrTVShow
from varken.helpers import hashit, connection_handler
@ -18,9 +18,33 @@ class SonarrAPI(object):
def __repr__(self):
return f"<sonarr-{self.server.id}>"
def get_series(self, id):
endpoint = '/api/v3/series/'
req = self.session.prepare_request(Request('GET', self.server.url + endpoint + str(id)))
get = connection_handler(self.session, req, self.server.verify_ssl)
if not get:
return
return SonarrTVShow(**get)
def get_episode(self, id):
endpoint = '/api/v3/episode'
params = {'episodeIds': id}
req = self.session.prepare_request(Request('GET', self.server.url + endpoint,params = params))
get = connection_handler(self.session, req, self.server.verify_ssl)
if not get:
return
return SonarrEpisode(**get[0])
def get_calendar(self, query="Missing"):
endpoint = '/api/calendar/'
endpoint = '/api/v3/calendar/'
today = str(date.today())
last_days = str(date.today() - timedelta(days=self.server.missing_days))
future = str(date.today() + timedelta(days=self.server.future_days))
@ -42,22 +66,23 @@ class SonarrAPI(object):
tv_shows = []
for show in get:
try:
tv_shows.append(SonarrTVShow(**show))
tv_shows.append(SonarrEpisode(**show))
except TypeError as e:
self.logger.error('TypeError has occurred : %s while creating SonarrTVShow structure for show. Data '
self.logger.error('TypeError has occurred : %s while creating SonarrEpisode structure for show. Data '
'attempted is: %s', e, show)
for show in tv_shows:
sxe = f'S{show.seasonNumber:0>2}E{show.episodeNumber:0>2}'
if show.hasFile:
for episode in tv_shows:
tvShow = self.get_series(episode.seriesId)
sxe = f'S{episode.seasonNumber:0>2}E{episode.episodeNumber:0>2}'
if episode.hasFile:
downloaded = 1
else:
downloaded = 0
if query == "Missing":
if show.monitored and not downloaded:
missing.append((show.series['title'], downloaded, sxe, show.title, show.airDateUtc, show.id))
if episode.monitored and not downloaded:
missing.append((tvShow.title, downloaded, sxe, episode.title, episode.airDateUtc, episode.seriesId))
else:
air_days.append((show.series['title'], downloaded, sxe, show.title, show.airDateUtc, show.id))
air_days.append((tvShow.title, downloaded, sxe, episode.title, episode.airDateUtc, episode.seriesId))
for series_title, dl_status, sxe, episode_title, air_date_utc, sonarr_id in (air_days or missing):
hash_id = hashit(f'{self.server.id}{series_title}{sxe}')
@ -85,41 +110,59 @@ class SonarrAPI(object):
def get_queue(self):
influx_payload = []
endpoint = '/api/queue'
endpoint = '/api/v3/queue'
now = datetime.now(timezone.utc).astimezone().isoformat()
pageSize = 250
params = {'pageSize': pageSize}
queueResponse = []
queue = []
req = self.session.prepare_request(Request('GET', self.server.url + endpoint))
req = self.session.prepare_request(Request('GET', self.server.url + endpoint,params=params))
get = connection_handler(self.session, req, self.server.verify_ssl)
if not get:
return
response = QueuePages(**get)
queueResponse.extend(response.records)
while response.totalRecords > response.page * response.pageSize:
page = response.page + 1
params = {'pageSize': pageSize, 'page': page}
req = self.session.prepare_request(Request('GET', self.server.url + endpoint,params=params))
get = connection_handler(self.session, req, self.server.verify_ssl)
if not get:
return
response = QueuePages(**get)
queueResponse.extend(response.records)
download_queue = []
for show in get:
for queueItem in queueResponse:
try:
download_queue.append(Queue(**show))
download_queue.append(SonarrQueue(**queueItem))
except TypeError as e:
self.logger.error('TypeError has occurred : %s while creating Queue structure. Data attempted is: '
'%s', e, show)
'%s', e, queueItem)
if not download_queue:
return
for show in download_queue:
for queueItem in download_queue:
tvShow = self.get_series(queueItem.seriesId)
episode = self.get_episode(queueItem.episodeId)
try:
sxe = f"S{show.episode['seasonNumber']:0>2}E{show.episode['episodeNumber']:0>2}"
sxe = f"S{episode.seasonNumber:0>2}E{episode.episodeNumber:0>2}"
except TypeError as e:
self.logger.error('TypeError has occurred : %s while processing the sonarr queue. \
Remove invalid queue entry. Data attempted is: %s', e, show)
Remove invalid queue entry. Data attempted is: %s', e, queueItem)
continue
if show.protocol.upper() == 'USENET':
if queueItem.protocol.upper() == 'USENET':
protocol_id = 1
else:
protocol_id = 0
queue.append((show.series['title'], show.episode['title'], show.protocol.upper(),
protocol_id, sxe, show.id, show.quality['quality']['name']))
queue.append((tvShow.title, episode.title, queueItem.protocol.upper(),
protocol_id, sxe, queueItem.seriesId, queueItem.quality['quality']['name']))
for series_title, episode_title, protocol, protocol_id, sxe, sonarr_id, quality in queue:
hash_id = hashit(f'{self.server.id}{series_title}{sxe}')

View file

@ -91,22 +91,13 @@ class UniFiServer(NamedTuple):
# 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
class QueuePages(NamedTuple):
page: int = None
pageSize: int = None
sortKey: str = None
sortDirection: str = None
totalRecords: str = None
records: list = None
# Ombi Structures
@ -184,35 +175,88 @@ class OmbiMovieRequest(NamedTuple):
# Sonarr
class SonarrTVShow(NamedTuple):
added: str = None
airTime: str = None
alternateTitles: list = None
certification: str = None
cleanTitle: str = None
ended: bool = None
firstAired: str = None
genres: list = None
id: int = None
images: list = None
imdbId: str = None
languageProfileId: int = None
monitored: bool = None
nextAiring: str = None
network: str = None
overview: str = None
path: str = None
previousAiring: str = None
qualityProfileId: int = None
ratings: dict = None
rootFolderPath: str = None
runtime: int = None
seasonFolder: bool = None
seasons: list = None
seriesType: str = None
sortTitle: str = None
statistics: dict = None
status: str = None
tags: list = None
title: str = None
titleSlug: str = None
tvdbId: int = None
tvMazeId: int = None
tvRageId: int = None
useSceneNumbering: bool = None
year: int = None
class SonarrEpisode(NamedTuple):
absoluteEpisodeNumber: int = None
airDate: str = None
airDateUtc: str = None
episodeFile: dict = None
episodeFileId: int = None
episodeNumber: int = None
grabbed: bool = 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
class SonarrQueue(NamedTuple):
downloadClient: str = None
downloadId: str = None
episodeId: int = None
id: int = None
indexer: str = None
language: dict = None
protocol: str = None
quality: dict = None
size: float = None
sizeleft: float = None
status: str = None
statusMessages: list = None
title: str = None
trackedDownloadState: str = None
trackedDownloadStatus: str = None
seriesId: int = None
# Radarr
class RadarrMovie(NamedTuple):
added: str = None
addOptions: str = None
alternativeTitles: list = None
alternateTitles: list = None
certification: str = None
cleanTitle: str = None
downloaded: bool = None
collection: dict = None
digitalRelease: str = None
folderName: str = None
genres: list = None
hasFile: bool = None
@ -221,32 +265,49 @@ class RadarrMovie(NamedTuple):
imdbId: str = None
inCinemas: str = None
isAvailable: bool = None
lastInfoSync: str = None
minimumAvailability: str = None
monitored: bool = None
movieFile: dict = None
originalTitle: str = 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
secondaryYear: int = None
secondaryYearSourceId: int = None
sizeOnDisk: int = None
sizeOnDisk: float = 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
title: str = None
# Radarr Queue
class RadarrQueue(NamedTuple):
customFormats: list = None
downloadClient: str = None
downloadId: str = None
id: int = None
indexer: str = None
languages: list = None
movieId: int = None
protocol: str = None
quality: dict = None
size: float = None
sizeleft: float = None
status: str = None
statusMessages: list = None
title: str = None
trackedDownloadState: str = None
trackedDownloadStatus: str = None
# Sickchill