1
1
"""Jellyseerr/Overseerr discovery features for Mediarr."""
2
2
import logging
3
+ import asyncio
3
4
from datetime import datetime
4
5
from ..common .tmdb_sensor import TMDBMediaSensor
5
6
import async_timeout
@@ -35,7 +36,7 @@ def unique_id(self):
35
36
return f"seer_mediarr_{ self ._content_type } _{ self ._url } "
36
37
return f"seer_mediarr_{ self ._content_type } _{ self ._url } "
37
38
38
- async def _fetch_media_list (self ):
39
+ async def _fetch_media_list (self , media_type = None ):
39
40
"""Fetch media list from Seer."""
40
41
try :
41
42
headers = {'X-Api-Key' : self ._seer_api_key }
@@ -51,8 +52,8 @@ async def _fetch_media_list(self):
51
52
url = f"{ self ._url } /api/v1/discover/tv"
52
53
params ["sortBy" ] = "popularity.desc"
53
54
elif self ._content_type == "discover" :
54
- # For discover, use movies as default
55
- media_type = "movies"
55
+ # Use provided media_type or default to movies
56
+ media_type = media_type or "movies"
56
57
url = f"{ self ._url } /api/v1/discover/{ media_type } "
57
58
else :
58
59
_LOGGER .error ("Unknown content type: %s" , self ._content_type )
@@ -70,65 +71,95 @@ async def _fetch_media_list(self):
70
71
except Exception as err :
71
72
_LOGGER .error ("Error fetching %s: %s" , self ._content_type , err )
72
73
return None
74
+ async def _fetch_all_requests (self ):
75
+ """Fetch all current requests from Overseerr/Jellyseerr."""
76
+ try :
77
+ url = f"{ self ._url } /api/v1/request"
78
+ headers = {"X-Api-Key" : self ._seer_api_key }
79
+ params = {"take" : 100 , "skip" : 0 } # Adjust take value as needed
80
+ all_requests = set ()
81
+
82
+ async with async_timeout .timeout (10 ):
83
+ async with self ._session .get (url , headers = headers , params = params ) as response :
84
+ if response .status == 200 :
85
+ data = await response .json ()
86
+ if data .get ('results' ):
87
+ for request in data ['results' ]:
88
+ if request .get ('media' ):
89
+ tmdb_id = request ['media' ].get ('tmdbId' )
90
+ if tmdb_id :
91
+ all_requests .add (str (tmdb_id ))
92
+
93
+ return all_requests
94
+ except Exception as err :
95
+ _LOGGER .error ("Error fetching all requests: %s" , err )
96
+ return set ()
97
+
98
+ async def _process_media_items (self , data , media_type , requested_ids ):
99
+ """Process media items in parallel."""
100
+ if not data or not data .get ('results' ):
101
+ return []
102
+
103
+ async def process_item (item ):
104
+ try :
105
+ tmdb_id = str (item .get ('id' ))
106
+ if tmdb_id in requested_ids :
107
+ return None
108
+
109
+ details = await self ._get_tmdb_details (tmdb_id , media_type )
110
+ if not details :
111
+ return None
112
+
113
+ poster_url , backdrop_url , main_backdrop_url = await self ._get_tmdb_images (tmdb_id , media_type )
114
+
115
+ return {
116
+ 'title' : details ['title' ],
117
+ 'overview' : details ['overview' ][:100 ] + '...' if details .get ('overview' ) else 'No overview available' ,
118
+ 'year' : details ['year' ],
119
+ 'poster' : str (poster_url or "" ),
120
+ 'fanart' : str (main_backdrop_url or backdrop_url or "" ),
121
+ 'banner' : str (backdrop_url or "" ),
122
+ 'release' : details ['year' ],
123
+ 'type' : 'Movie' if media_type == 'movie' else 'TV Show' ,
124
+ 'flag' : 1 ,
125
+ 'id' : tmdb_id
126
+ }
127
+ except Exception as err :
128
+ _LOGGER .error ("Error processing item %s: %s" , tmdb_id , err )
129
+ return None
130
+
131
+ # Process items in parallel
132
+ tasks = [process_item (item ) for item in data ['results' ]]
133
+ results = await asyncio .gather (* tasks , return_exceptions = True )
134
+
135
+ # Filter out None values and handle any exceptions
136
+ return [item for item in results if item is not None and not isinstance (item , Exception )]
73
137
74
138
async def async_update (self ):
75
139
"""Update the sensor."""
76
140
try :
141
+ # Fetch all current requests first
142
+ requested_ids = await self ._fetch_all_requests ()
77
143
all_items = []
78
144
79
145
if self ._content_type == "discover" :
80
- # For discover, fetch both movies and TV
146
+ # Fetch both movies and TV
81
147
for media_type in ['movies' , 'tv' ]:
82
- data = await self ._fetch_media_list ()
83
- if data and data .get ('results' ):
84
- for item in data ['results' ]:
85
- tmdb_id = item .get ('id' )
86
- media_type = 'movie' if media_type == 'movies' else 'tv'
87
-
88
- details = await self ._get_tmdb_details (tmdb_id , media_type )
89
- if not details :
90
- continue
91
-
92
- poster_url , backdrop_url , main_backdrop_url = await self ._get_tmdb_images (tmdb_id , media_type )
93
-
94
- all_items .append ({
95
- 'title' : details ['title' ],
96
- 'overview' : details ['overview' ][:100 ] + '...' ,
97
- 'year' : details ['year' ],
98
- 'poster' : str (poster_url or "" ),
99
- 'fanart' : str (main_backdrop_url or backdrop_url or "" ),
100
- 'banner' : str (backdrop_url or "" ),
101
- 'release' : details ['year' ],
102
- 'type' : 'Movie' if media_type == 'movie' else 'TV Show' ,
103
- 'flag' : 1
104
- })
148
+ data = await self ._fetch_media_list (media_type ) # Pass media_type here
149
+ processed_items = await self ._process_media_items (
150
+ data ,
151
+ 'movie' if media_type == 'movies' else 'tv' ,
152
+ requested_ids
153
+ )
154
+ all_items .extend (processed_items )
105
155
else :
106
- # For trending and popular, fetch single type
156
+ # Fetch single type (trending, popular movies, or popular TV)
107
157
data = await self ._fetch_media_list ()
108
- if data and data .get ('results' ):
109
- for item in data ['results' ]:
110
- media_type = 'movie' if self ._content_type == 'popular_movies' else 'tv'
111
- tmdb_id = item .get ('id' )
112
-
113
- details = await self ._get_tmdb_details (tmdb_id , media_type )
114
- if not details :
115
- continue
116
-
117
- poster_url , backdrop_url , main_backdrop_url = await self ._get_tmdb_images (tmdb_id , media_type )
118
-
119
- all_items .append ({
120
- 'title' : details ['title' ],
121
- 'overview' : details ['overview' ][:100 ] + '...' ,
122
- 'year' : details ['year' ],
123
- 'poster' : str (poster_url or "" ),
124
- 'fanart' : str (main_backdrop_url or backdrop_url or "" ),
125
- 'banner' : str (backdrop_url or "" ),
126
- 'release' : details ['year' ],
127
- 'type' : 'Movie' if media_type == 'movie' else 'TV Show' ,
128
- 'flag' : 1
129
- })
130
-
131
- # Sort and limit items
158
+ media_type = 'movie' if self ._content_type == 'popular_movies' else 'tv'
159
+ processed_items = await self ._process_media_items (data , media_type , requested_ids )
160
+ all_items .extend (processed_items )
161
+
162
+ # Ensure max_items limit is respected
132
163
all_items = all_items [:self ._max_items ]
133
164
134
165
if not all_items :
@@ -148,4 +179,4 @@ async def async_update(self):
148
179
_LOGGER .error ("Error updating %s sensor: %s" , self ._content_type , err )
149
180
self ._state = 0
150
181
self ._attributes = {'data' : []}
151
- self ._available = False
182
+ self ._available = False
0 commit comments