Repository: pymedusa/Medusa

Issue:
Add Recommended Shows failed
**Describe the bug**
A clear and concise description of what the bug is.
When doing a search for new recommended shows, Nothing is showing. Only warning appears in the log.

**To Reproduce**
Steps to reproduce the behavior:
1. Add Recommended Shows
2. Click on "Search for new recommended shows from imdb"
2. Look in the Log

**Expected behavior**
A clear and concise description of what you expected to happen.
Showing the recommended shows

**Screenshots**
If applicable, add screenshots to help explain your problem.


**Medusa (please complete the following information):**
 - OS: [e.g. ubuntu 14.04 x64] Rocky Linux 8.4
 - Branch: [e.g. master, develop] master
 - Commit: [e.g. c65ca2] 25e7b6072201a8a73e1220ee5ffe13cbefce45f8 
 - Python version: [e.g. 3.6.8] 3.8.6
 - Database version: [e.g. 44.12] 44.18

**Debug logs (at least 50 lines):**
General > Advanced Settings > Enable debug
(I did the steps 4 times)
<details>

```
2021-08-14 12:48:44 INFO	GENERICQUEUESCHEDULER-UPDATE-RECOMMENDED-IMDB :: [25e7b60] Finished caching recommended shows
2021-08-14 12:48:44 INFO	GENERICQUEUESCHEDULER-UPDATE-RECOMMENDED-IMDB :: [25e7b60] Could not get imdb recommended shows because of error: 'NoneType' object is not iterable
2021-08-14 12:48:44 WARNING	GENERICQUEUESCHEDULER-UPDATE-RECOMMENDED-IMDB :: [25e7b60] Could not parse show tt10293938 with error: KeyError('genres')
2021-08-14 12:48:44 INFO	GENERICQUEUESCHEDULER-UPDATE-RECOMMENDED-IMDB :: [25e7b60] Started caching recommended shows
2021-08-14 12:43:59 INFO	GENERICQUEUESCHEDULER-UPDATE-RECOMMENDED-IMDB :: [25e7b60] Finished caching recommended shows
2021-08-14 12:43:59 INFO	GENERICQUEUESCHEDULER-UPDATE-RECOMMENDED-IMDB :: [25e7b60] Could not get imdb recommended shows because of error: 'NoneType' object is not iterable
2021-08-14 12:43:59 WARNING	GENERICQUEUESCHEDULER-UPDATE-RECOMMENDED-IMDB :: [25e7b60] Could not parse show tt10293938 with error: KeyError('genres')
2021-08-14 12:43:58 INFO	GENERICQUEUESCHEDULER-UPDATE-RECOMMENDED-IMDB :: [25e7b60] Started caching recommended shows
2021-08-14 12:42:28 INFO	SEARCHQUEUE-DAILY-SEARCH :: [25e7b60] No needed episodes found
2021-08-14 12:42:25 INFO	SEARCHQUEUE-DAILY-SEARCH :: [25e7b60] Using daily search providers
2021-08-14 12:42:25 INFO	SEARCHQUEUE-DAILY-SEARCH :: [25e7b60] Beginning daily search for new episodes
2021-08-14 12:40:52 INFO	GENERICQUEUESCHEDULER-UPDATE-RECOMMENDED-IMDB :: [25e7b60] Finished caching recommended shows
2021-08-14 12:40:52 INFO	GENERICQUEUESCHEDULER-UPDATE-RECOMMENDED-IMDB :: [25e7b60] Could not get imdb recommended shows because of error: 'NoneType' object is not iterable
2021-08-14 12:40:52 WARNING	GENERICQUEUESCHEDULER-UPDATE-RECOMMENDED-IMDB :: [25e7b60] Could not parse show tt10293938 with error: KeyError('genres')
2021-08-14 12:40:52 INFO	GENERICQUEUESCHEDULER-UPDATE-RECOMMENDED-IMDB :: [25e7b60] Started caching recommended shows
2021-08-14 12:38:43 INFO	GENERICQUEUESCHEDULER-UPDATE-RECOMMENDED-IMDB :: [25e7b60] Finished caching recommended shows
2021-08-14 12:38:43 INFO	GENERICQUEUESCHEDULER-UPDATE-RECOMMENDED-IMDB :: [25e7b60] Could not get imdb recommended shows because of error: 'NoneType' object is not iterable
2021-08-14 12:38:43 WARNING	GENERICQUEUESCHEDULER-UPDATE-RECOMMENDED-IMDB :: [25e7b60] Could not parse show tt10293938 with error: KeyError('genres')
2021-08-14 12:38:43 INFO	GENERICQUEUESCHEDULER-UPDATE-RECOMMENDED-IMDB :: [25e7b60] Started caching recommended shows
```

</details>

**Additional context**
Add any other context about the problem here.



Discussion:
Do trakt, anidb, anilist work?
> Do trakt, anidb, anilist work?

I do not use trakt, so I can not test this. anidb and anilist do work.

Resolving patch:
diff --git a/medusa/helpers/anidb.py b/medusa/helpers/anidb.py
--- a/medusa/helpers/anidb.py
+++ b/medusa/helpers/anidb.py
@@ -11,8 +11,7 @@
 from medusa.cache import anidb_cache
 from medusa.helper.exceptions import AnidbAdbaConnectionException
 from medusa.logger.adapters.style import BraceAdapter
-
-import six
+from medusa.show.recommendations.recommended import create_key
 
 log = BraceAdapter(logging.getLogger(__name__))
 log.logger.addHandler(logging.NullHandler())
@@ -48,15 +47,6 @@ def set_up_anidb_connection():
     return app.ADBA_CONNECTION.authed()
 
 
-def create_key(namespace, fn, **kw):
-    def generate_key(*args, **kw):
-        show_key = namespace + '|' + args[0]
-        if six.PY2:
-            return show_key.encode('utf-8')
-        return show_key
-    return generate_key
-
-
 @anidb_cache.cache_on_arguments(namespace='anidb', function_key_generator=create_key)
 def get_release_groups_for_anime(series_name):
     """Get release groups for an anidb anime."""
diff --git a/medusa/show/recommendations/imdb.py b/medusa/show/recommendations/imdb.py
--- a/medusa/show/recommendations/imdb.py
+++ b/medusa/show/recommendations/imdb.py
@@ -16,6 +16,7 @@
     BasePopular,
     RecommendedShow,
     cached_get_imdb_series_details,
+    cached_get_imdb_series_genres,
     create_key_from_series,
 )
 
@@ -77,44 +78,53 @@ def fetch_popular_shows(self):
             show_details = None
             imdb_id = series['imdb_tt'] = imdb_show['id'].strip('/').split('/')[-1]
 
-            if imdb_id:
-                try:
-                    show_details = cached_get_imdb_series_details(imdb_id)
-                except RequestException as error:
-                    log.warning('Could not get show details for {imdb_id} with error: {error!r}',
-                                {'imdb_id': imdb_id, 'error': error})
-
-                if show_details:
-                    try:
-                        series['year'] = imdb_show.get('year')
-                        series['name'] = imdb_show['title']
-                        series['image_url_large'] = imdb_show['image']['url']
-                        series['image_path'] = posixpath.join('images', 'imdb_popular',
-                                                              os.path.basename(series['image_url_large']))
-                        series['image_url'] = '{0}{1}'.format(imdb_show['image']['url'].split('V1')[0], '_SY600_AL_.jpg')
-                        series['imdb_url'] = 'http://www.imdb.com{imdb_id}'.format(imdb_id=imdb_show['id'])
-                        series['votes'] = show_details['ratings'].get('ratingCount', 0)
-                        series['outline'] = show_details['plot'].get('outline', {}).get('text')
-                        series['rating'] = show_details['ratings'].get('rating', 0)
-                        series['genres'] = show_details['genres'].get('genres')
-                    except Exception as error:
-                        log.warning('Could not parse show {imdb_id} with error: {error!r}',
-                                    {'imdb_id': imdb_id, 'error': error})
-                else:
-                    continue
-
-            if all([series['year'], series['name'], series['imdb_tt']]):
-                try:
-                    recommended_show = self._create_recommended_show(series)
-                    if recommended_show:
-                        recommended_show.save_to_db()
-                        result.append(recommended_show)
-                except RequestException:
-                    log.warning(
-                        u'Could not connect to indexers to check if you already have'
-                        u' this show in your library: {show} ({year})',
-                        {'show': series['name'], 'year': series['name']}
-                    )
+            if not imdb_id:
+                continue
+
+            series['year'] = imdb_show.get('year')
+            series['name'] = imdb_show['title']
+            series['image_url_large'] = imdb_show['image']['url']
+            series['image_path'] = posixpath.join(
+                'images', 'imdb_popular', os.path.basename(series['image_url_large'])
+            )
+            series['image_url'] = '{0}{1}'.format(imdb_show['image']['url'].split('V1')[0], '_SY600_AL_.jpg')
+            series['imdb_url'] = 'http://www.imdb.com{imdb_id}'.format(imdb_id=imdb_show['id'])
+
+            show_details = {}
+            show_genres = {}
+            try:
+                show_details = cached_get_imdb_series_details(imdb_id)
+                show_genres = cached_get_imdb_series_genres(imdb_id)
+            except Exception as error:
+                log.warning('Could not get show details for {imdb_id} with error: {error}',
+                            {'imdb_id': imdb_id, 'error': error})
+
+            if not show_details:
+                continue
+
+            # Get details.
+            try:
+                series['votes'] = show_details.get('ratings', {}).get('ratingCount', 0)
+                series['outline'] = show_details.get('plot', {}).get('outline', {}).get('text')
+                series['rating'] = show_details.get('ratings', {}).get('rating', 0)
+            except Exception as error:
+                log.warning('Could not parse show {imdb_id} with error: {error!r}',
+                            {'imdb_id': imdb_id, 'error': error})
+
+            series['genres'] = show_genres.get('genres', [])
+
+        if all([series['year'], series['name'], series['imdb_tt']]):
+            try:
+                recommended_show = self._create_recommended_show(series)
+                if recommended_show:
+                    recommended_show.save_to_db()
+                    result.append(recommended_show)
+            except RequestException:
+                log.warning(
+                    u'Could not connect to indexers to check if you already have'
+                    u' this show in your library: {show} ({year})',
+                    {'show': series['name'], 'year': series['name']}
+                )
 
         return result
 
diff --git a/medusa/show/recommendations/recommended.py b/medusa/show/recommendations/recommended.py
--- a/medusa/show/recommendations/recommended.py
+++ b/medusa/show/recommendations/recommended.py
@@ -347,8 +347,16 @@ def get_categories():
     return categories
 
 
+def create_key(namespace, fn, **kw):
+    """Create key out of namespace + firs arg."""
+    def generate_key(*args, **kw):
+        show_key = f'{namespace}|{args[0]}'
+        return show_key
+    return generate_key
+
+
 @LazyApi.load_anidb_api
-@recommended_series_cache.cache_on_arguments()
+@recommended_series_cache.cache_on_arguments(namespace='tvdb_to_anidb', function_key_generator=create_key)
 def cached_tvdb_to_aid(tvdb_id):
     """
     Try to match an anidb id with a tvdb id.
@@ -359,7 +367,7 @@ def cached_tvdb_to_aid(tvdb_id):
 
 
 @LazyApi.load_anidb_api
-@recommended_series_cache.cache_on_arguments()
+@recommended_series_cache.cache_on_arguments(namespace='anidb_to_tvdb', function_key_generator=create_key)
 def cached_aid_to_tvdb(aid):
     """
     Try to match a tvdb id with an anidb id.
@@ -370,16 +378,31 @@ def cached_aid_to_tvdb(aid):
 
 
 @LazyApi.load_imdb_api
-@recommended_series_cache.cache_on_arguments()
+@recommended_series_cache.cache_on_arguments(namespace='series_details', function_key_generator=create_key)
 def cached_get_imdb_series_details(imdb_id):
     """
     Request the series details from the imdbpie api.
 
     Use dogpile cache to return a cached id if available.
     """
-    title_detailed = LazyApi.imdb_api.get_title(imdb_id)
-    title_detailed['genres'] = LazyApi.imdb_api.get_title_genres(imdb_id)
-    return title_detailed
+    details = LazyApi.imdb_api.get_title(imdb_id)
+    if not details:
+        raise Exception(f'Could not get imdb details from {imdb_id}')
+    return details
+
+
+@LazyApi.load_imdb_api
+@recommended_series_cache.cache_on_arguments(namespace='series_genres', function_key_generator=create_key)
+def cached_get_imdb_series_genres(imdb_id):
+    """
+    Request the series genres from the imdbpie api.
+
+    Use dogpile cache to return a cached id if available.
+    """
+    genres = LazyApi.imdb_api.get_title_genres(imdb_id)
+    if not genres:
+        raise Exception(f'Could not get imdb genres from {imdb_id}')
+    return genres
 
 
 def create_key_from_series(namespace, fn, **kw):


Test patch: