Repository: yt-dlp/yt-dlp

Issue:
[Site Request] [Funimation] Playlist extractor
<!--

######################################################################
  WARNING!
  IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE
######################################################################

-->


## Checklist

<!--
Carefully read and work through this check list in order to prevent the most common mistakes and misuse of yt-dlp:
- First of, make sure you are using the latest version of yt-dlp. Run `yt-dlp --version` and ensure your version is 2021.06.23. If it's not, see https://github.com/yt-dlp/yt-dlp on how to update. Issues with outdated version will be REJECTED.
- Search the bugtracker for similar site feature requests: https://github.com/yt-dlp/yt-dlp. DO NOT post duplicates.
- Finally, put x into all relevant boxes like this [x] (Dont forget to delete the empty space)
-->

- [X] I'm reporting a site feature request
- [X] I've verified that I'm running yt-dlp version **2021.06.23**
- [X] I've searched the bugtracker for similar site feature requests including closed ones


## Description

<!--
Provide an explanation of your site feature request in an arbitrary form. Please make sure the description is worded well enough to be understood, see https://github.com/ytdl-org/youtube-dl#is-the-description-of-the-issue-itself-sufficient. Provide any additional information, suggested solution and as much context and examples as possible.
-->

@Mevious I tried your changes but I still can't get it to work unless I did something wrong? https://github.com/Jules-A/yt-dlp/tree/funplaylist 

```
[funimation:playlist] Logging in
[debug] [funimation:playlist] Extracting URL: https://www.funimation.com/shows/c3-anime
[funimation:playlist] c3-anime: Downloading webpage
WARNING: [funimation:playlist] c3-anime: Failed to parse JSON Expecting value: line 1 column 1 (char 0)
[funimation:playlist] c3-anime: Downloading JSON metadata
[download] Downloading playlist: None
[funimation:playlist] playlist None: Collected 0 videos; downloading 0 of them
[download] Finished downloading playlist: None
```


Discussion:

Resolving patch:
diff --git a/yt_dlp/extractor/extractors.py b/yt_dlp/extractor/extractors.py
--- a/yt_dlp/extractor/extractors.py
+++ b/yt_dlp/extractor/extractors.py
@@ -455,7 +455,10 @@
     FrontendMastersCourseIE
 )
 from .fujitv import FujiTVFODPlus7IE
-from .funimation import FunimationIE
+from .funimation import (
+    FunimationIE,
+    FunimationShowIE
+)
 from .funk import FunkIE
 from .fusion import FusionIE
 from .gaia import GaiaIE
diff --git a/yt_dlp/extractor/funimation.py b/yt_dlp/extractor/funimation.py
--- a/yt_dlp/extractor/funimation.py
+++ b/yt_dlp/extractor/funimation.py
@@ -2,12 +2,14 @@
 from __future__ import unicode_literals
 
 import random
+import re
 import string
 
 from .common import InfoExtractor
 from ..compat import compat_HTTPError
 from ..utils import (
     determine_ext,
+    dict_get,
     int_or_none,
     js_to_json,
     urlencode_postdata,
@@ -176,3 +178,53 @@ def _get_subtitles(self, url, video_id, display_id):
                 language += '_CC'
             subtitles.setdefault(language, []).append(url_element)
         return subtitles
+
+
+class FunimationShowIE(FunimationIE):
+    IE_NAME = 'funimation:show'
+    _VALID_URL = r'(?P<url>https?://(?:www\.)?funimation(?:\.com|now\.uk)/(?P<locale>[^/]+)?/?shows/(?P<id>[^/?#&]+))/?(?:[?#]|$)'
+
+    _TESTS = [{
+        'url': 'https://www.funimation.com/en/shows/sk8-the-infinity',
+        'info_dict': {
+            'id': 1315000,
+            'title': 'SK8 the Infinity'
+        },
+        'playlist_count': 13,
+        'params': {
+            'skip_download': True,
+        },
+    }, {
+        # without lang code
+        'url': 'https://www.funimation.com/shows/ouran-high-school-host-club/',
+        'info_dict': {
+            'id': 39643,
+            'title': 'Ouran High School Host Club'
+        },
+        'playlist_count': 26,
+        'params': {
+            'skip_download': True,
+        },
+    }]
+
+    def _real_extract(self, url):
+        base_url, locale, display_id = re.match(self._VALID_URL, url).groups()
+
+        show_info = self._download_json(
+            'https://title-api.prd.funimationsvc.com/v2/shows/%s?region=US&deviceType=web&locale=%s'
+            % (display_id, locale or 'en'), display_id)
+        items = self._download_json(
+            'https://prod-api-funimationnow.dadcdigital.com/api/funimation/episodes/?limit=99999&title_id=%s'
+            % show_info.get('id'), display_id).get('items')
+        vod_items = map(lambda k: dict_get(k, ('mostRecentSvod', 'mostRecentAvod')).get('item'), items)
+
+        return {
+            '_type': 'playlist',
+            'id': show_info['id'],
+            'title': show_info['name'],
+            'entries': [
+                self.url_result(
+                    '%s/%s' % (base_url, vod_item.get('episodeSlug')), FunimationIE.ie_key(),
+                    vod_item.get('episodeId'), vod_item.get('episodeName'))
+                for vod_item in sorted(vod_items, key=lambda x: x.get('episodeOrder'))],
+        }


Test patch: