updated to support Radarr and Sonarr V3 Api
This commit is contained in:
		
							parent
							
								
									c6b8dde29a
								
							
						
					
					
						commit
						57028cd26c
					
				
					 3 changed files with 198 additions and 70 deletions
				
			
		|  | @ -2,7 +2,7 @@ from logging import getLogger | ||||||
| from requests import Session, Request | from requests import Session, Request | ||||||
| from datetime import datetime, timezone | 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 | from varken.helpers import hashit, connection_handler | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -18,8 +18,19 @@ class RadarrAPI(object): | ||||||
|     def __repr__(self): |     def __repr__(self): | ||||||
|         return f"<radarr-{self.server.id}>" |         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): |     def get_missing(self): | ||||||
|         endpoint = '/api/movie' |         endpoint = '/api/v3/movie' | ||||||
|         now = datetime.now(timezone.utc).astimezone().isoformat() |         now = datetime.now(timezone.utc).astimezone().isoformat() | ||||||
|         influx_payload = [] |         influx_payload = [] | ||||||
|         missing = [] |         missing = [] | ||||||
|  | @ -37,7 +48,7 @@ class RadarrAPI(object): | ||||||
|             return |             return | ||||||
| 
 | 
 | ||||||
|         for movie in movies: |         for movie in movies: | ||||||
|             if movie.monitored and not movie.downloaded: |             if movie.monitored and not movie.hasFile: | ||||||
|                 if movie.isAvailable: |                 if movie.isAvailable: | ||||||
|                     ma = 0 |                     ma = 0 | ||||||
|                 else: |                 else: | ||||||
|  | @ -69,32 +80,45 @@ class RadarrAPI(object): | ||||||
|         self.dbmanager.write_points(influx_payload) |         self.dbmanager.write_points(influx_payload) | ||||||
| 
 | 
 | ||||||
|     def get_queue(self): |     def get_queue(self): | ||||||
|         endpoint = '/api/queue' |         endpoint = '/api/v3/queue' | ||||||
|         now = datetime.now(timezone.utc).astimezone().isoformat() |         now = datetime.now(timezone.utc).astimezone().isoformat() | ||||||
|         influx_payload = [] |         influx_payload = [] | ||||||
|  |         pageSize = 250 | ||||||
|  |         params = {'pageSize': pageSize} | ||||||
|  |         queueResponse = [] | ||||||
|         queue = [] |         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) |         get = connection_handler(self.session, req, self.server.verify_ssl) | ||||||
| 
 |  | ||||||
|         if not get: |         if not get: | ||||||
|             return |             return | ||||||
|  |          | ||||||
|  |         response = QueuePages(**get) | ||||||
|  |         queueResponse.extend(response.records) | ||||||
| 
 | 
 | ||||||
|         for movie in get: |         while response.totalRecords > response.page * response.pageSize: | ||||||
|             try: |             page = response.page + 1 | ||||||
|                 movie['movie'] = RadarrMovie(**movie['movie']) |             params = {'pageSize': pageSize, 'page': page} | ||||||
|             except TypeError as e: |             req = self.session.prepare_request(Request('GET', self.server.url + endpoint,params=params)) | ||||||
|                 self.logger.error('TypeError has occurred : %s while creating RadarrMovie structure', e) |             get = connection_handler(self.session, req, self.server.verify_ssl)            | ||||||
|  |             if not get: | ||||||
|                 return |                 return | ||||||
| 
 | 
 | ||||||
|         try: |             response = QueuePages(**get) | ||||||
|             download_queue = [Queue(**movie) for movie in get] |             queueResponse.extend(response.records) | ||||||
|         except TypeError as e: | 
 | ||||||
|             self.logger.error('TypeError has occurred : %s while creating Queue structure', e) |         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 |             return | ||||||
| 
 | 
 | ||||||
|         for queue_item in download_queue: |         for queue_item in download_queue: | ||||||
|             movie = queue_item.movie |             movie = self.get_movie(queue_item.movieId) | ||||||
| 
 | 
 | ||||||
|             name = f'{movie.title} ({movie.year})' |             name = f'{movie.title} ({movie.year})' | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ from logging import getLogger | ||||||
| from requests import Session, Request | from requests import Session, Request | ||||||
| from datetime import datetime, timezone, date, timedelta | 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 | from varken.helpers import hashit, connection_handler | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -18,9 +18,33 @@ class SonarrAPI(object): | ||||||
| 
 | 
 | ||||||
|     def __repr__(self): |     def __repr__(self): | ||||||
|         return f"<sonarr-{self.server.id}>" |         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"): |     def get_calendar(self, query="Missing"): | ||||||
|         endpoint = '/api/calendar/' |         endpoint = '/api/v3/calendar/' | ||||||
|         today = str(date.today()) |         today = str(date.today()) | ||||||
|         last_days = str(date.today() - timedelta(days=self.server.missing_days)) |         last_days = str(date.today() - timedelta(days=self.server.missing_days)) | ||||||
|         future = str(date.today() + timedelta(days=self.server.future_days)) |         future = str(date.today() + timedelta(days=self.server.future_days)) | ||||||
|  | @ -42,22 +66,23 @@ class SonarrAPI(object): | ||||||
|         tv_shows = [] |         tv_shows = [] | ||||||
|         for show in get: |         for show in get: | ||||||
|             try: |             try: | ||||||
|                 tv_shows.append(SonarrTVShow(**show)) |                 tv_shows.append(SonarrEpisode(**show)) | ||||||
|             except TypeError as e: |             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) |                                   'attempted is: %s', e, show) | ||||||
| 
 | 
 | ||||||
|         for show in tv_shows: |         for episode in tv_shows: | ||||||
|             sxe = f'S{show.seasonNumber:0>2}E{show.episodeNumber:0>2}' |             tvShow = self.get_series(episode.seriesId) | ||||||
|             if show.hasFile: |             sxe = f'S{episode.seasonNumber:0>2}E{episode.episodeNumber:0>2}' | ||||||
|  |             if episode.hasFile: | ||||||
|                 downloaded = 1 |                 downloaded = 1 | ||||||
|             else: |             else: | ||||||
|                 downloaded = 0 |                 downloaded = 0 | ||||||
|             if query == "Missing": |             if query == "Missing": | ||||||
|                 if show.monitored and not downloaded: |                 if episode.monitored and not downloaded: | ||||||
|                     missing.append((show.series['title'], downloaded, sxe, show.title, show.airDateUtc, show.id)) |                     missing.append((tvShow.title, downloaded, sxe, episode.title, episode.airDateUtc, episode.seriesId)) | ||||||
|             else: |             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): |         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}') |             hash_id = hashit(f'{self.server.id}{series_title}{sxe}') | ||||||
|  | @ -85,41 +110,59 @@ class SonarrAPI(object): | ||||||
| 
 | 
 | ||||||
|     def get_queue(self): |     def get_queue(self): | ||||||
|         influx_payload = [] |         influx_payload = [] | ||||||
|         endpoint = '/api/queue' |         endpoint = '/api/v3/queue' | ||||||
|         now = datetime.now(timezone.utc).astimezone().isoformat() |         now = datetime.now(timezone.utc).astimezone().isoformat() | ||||||
|  |         pageSize = 250 | ||||||
|  |         params = {'pageSize': pageSize} | ||||||
|  |         queueResponse = [] | ||||||
|         queue = [] |         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) |         get = connection_handler(self.session, req, self.server.verify_ssl) | ||||||
| 
 |  | ||||||
|         if not get: |         if not get: | ||||||
|             return |             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 = [] |         download_queue = [] | ||||||
|         for show in get: |         for queueItem in queueResponse: | ||||||
|             try: |             try: | ||||||
|                 download_queue.append(Queue(**show)) |                 download_queue.append(SonarrQueue(**queueItem)) | ||||||
|             except TypeError as e: |             except TypeError as e: | ||||||
|                 self.logger.error('TypeError has occurred : %s while creating Queue structure. Data attempted is: ' |                 self.logger.error('TypeError has occurred : %s while creating Queue structure. Data attempted is: ' | ||||||
|                                   '%s', e, show) |                                   '%s', e, queueItem) | ||||||
|         if not download_queue: |         if not download_queue: | ||||||
|             return |             return | ||||||
| 
 | 
 | ||||||
|         for show in download_queue: |         for queueItem in download_queue: | ||||||
|  |             tvShow = self.get_series(queueItem.seriesId) | ||||||
|  |             episode = self.get_episode(queueItem.episodeId) | ||||||
|             try: |             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: |             except TypeError as e: | ||||||
|                 self.logger.error('TypeError has occurred : %s while processing the sonarr queue. \ |                 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 |                 continue | ||||||
| 
 | 
 | ||||||
|             if show.protocol.upper() == 'USENET': |             if queueItem.protocol.upper() == 'USENET': | ||||||
|                 protocol_id = 1 |                 protocol_id = 1 | ||||||
|             else: |             else: | ||||||
|                 protocol_id = 0 |                 protocol_id = 0 | ||||||
| 
 | 
 | ||||||
|             queue.append((show.series['title'], show.episode['title'], show.protocol.upper(), |             queue.append((tvShow.title, episode.title, queueItem.protocol.upper(), | ||||||
|                           protocol_id, sxe, show.id, show.quality['quality']['name'])) |                           protocol_id, sxe, queueItem.seriesId, queueItem.quality['quality']['name'])) | ||||||
| 
 | 
 | ||||||
|         for series_title, episode_title, protocol, protocol_id, sxe, sonarr_id, quality 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}') |             hash_id = hashit(f'{self.server.id}{series_title}{sxe}') | ||||||
|  |  | ||||||
|  | @ -91,22 +91,13 @@ class UniFiServer(NamedTuple): | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| # Shared | # Shared | ||||||
| class Queue(NamedTuple): | class QueuePages(NamedTuple): | ||||||
|     downloadId: str = None |     page: int = None | ||||||
|     episode: dict = None |     pageSize: int = None | ||||||
|     estimatedCompletionTime: str = None |     sortKey: str = None | ||||||
|     id: int = None |     sortDirection: str = None | ||||||
|     movie: dict = None |     totalRecords: str = None | ||||||
|     protocol: str = None |     records: list = 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 | # Ombi Structures | ||||||
|  | @ -184,35 +175,88 @@ class OmbiMovieRequest(NamedTuple): | ||||||
| 
 | 
 | ||||||
| # Sonarr | # Sonarr | ||||||
| class SonarrTVShow(NamedTuple): | 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 |     absoluteEpisodeNumber: int = None | ||||||
|     airDate: str = None |     airDate: str = None | ||||||
|     airDateUtc: str = None |     airDateUtc: str = None | ||||||
|     episodeFile: dict = None |  | ||||||
|     episodeFileId: int = None |     episodeFileId: int = None | ||||||
|     episodeNumber: int = None |     episodeNumber: int = None | ||||||
|  |     grabbed: bool = None | ||||||
|     hasFile: bool = None |     hasFile: bool = None | ||||||
|     id: int = None |     id: int = None | ||||||
|     lastSearchTime: str = None |  | ||||||
|     monitored: bool = None |     monitored: bool = None | ||||||
|     overview: str = None |     overview: str = None | ||||||
|     sceneAbsoluteEpisodeNumber: int = None |  | ||||||
|     sceneEpisodeNumber: int = None |  | ||||||
|     sceneSeasonNumber: int = None |  | ||||||
|     seasonNumber: int = None |     seasonNumber: int = None | ||||||
|     series: dict = None |  | ||||||
|     seriesId: int = None |     seriesId: int = None | ||||||
|     title: str = None |     title: str = None | ||||||
|     unverifiedSceneNumbering: bool = 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 | # Radarr | ||||||
| class RadarrMovie(NamedTuple): | class RadarrMovie(NamedTuple): | ||||||
|     added: str = None |     added: str = None | ||||||
|     addOptions: str = None |     alternateTitles: list = None | ||||||
|     alternativeTitles: list = None |  | ||||||
|     certification: str = None |     certification: str = None | ||||||
|     cleanTitle: str = None |     cleanTitle: str = None | ||||||
|     downloaded: bool = None |     collection: dict = None | ||||||
|  |     digitalRelease: str = None | ||||||
|     folderName: str = None |     folderName: str = None | ||||||
|     genres: list = None |     genres: list = None | ||||||
|     hasFile: bool = None |     hasFile: bool = None | ||||||
|  | @ -221,32 +265,49 @@ class RadarrMovie(NamedTuple): | ||||||
|     imdbId: str = None |     imdbId: str = None | ||||||
|     inCinemas: str = None |     inCinemas: str = None | ||||||
|     isAvailable: bool = None |     isAvailable: bool = None | ||||||
|     lastInfoSync: str = None |  | ||||||
|     minimumAvailability: str = None |     minimumAvailability: str = None | ||||||
|     monitored: bool = None |     monitored: bool = None | ||||||
|     movieFile: dict = None |     movieFile: dict = None | ||||||
|  |     originalTitle: str = None | ||||||
|     overview: str = None |     overview: str = None | ||||||
|     path: str = None |     path: str = None | ||||||
|     pathState: str = None |  | ||||||
|     physicalRelease: str = None |     physicalRelease: str = None | ||||||
|     physicalReleaseNote: str = None |  | ||||||
|     profileId: int = None |  | ||||||
|     qualityProfileId: int = None |     qualityProfileId: int = None | ||||||
|     ratings: dict = None |     ratings: dict = None | ||||||
|     runtime: int = None |     runtime: int = None | ||||||
|     secondaryYear: str = None |     secondaryYear: int = None | ||||||
|     secondaryYearSourceId: int = None |     secondaryYearSourceId: int = None | ||||||
|     sizeOnDisk: int = None |     sizeOnDisk: float = None | ||||||
|     sortTitle: str = None |     sortTitle: str = None | ||||||
|     status: str = None |     status: str = None | ||||||
|     studio: str = None |     studio: str = None | ||||||
|     tags: list = None |     tags: list = None | ||||||
|     title: str = None |  | ||||||
|     titleSlug: str = None |     titleSlug: str = None | ||||||
|     tmdbId: int = None |     tmdbId: int = None | ||||||
|     website: str = None |     website: str = None | ||||||
|     year: int = None |     year: int = None | ||||||
|     youTubeTrailerId: str = 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 | # Sickchill | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue