We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Eporner stuck at invoked download
<!--

######################################################################
  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 youtube-dl:
- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is 2020.07.28. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.
- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.
- Make sure that all URLs and arguments with special characters are properly quoted or escaped as explained in http://yt-dl.org/escape.
- Search the bugtracker for similar issues: http://yt-dl.org/search-issues. DO NOT post duplicates.
- Read bugs section in FAQ: http://yt-dl.org/reporting
- Finally, put x into all relevant boxes (like this [x])
-->

- [x] I'm reporting a broken site support issue
- [x] I've verified that I'm running youtube-dl version **2020.07.28**
- [x] I've checked that all provided URLs are alive and playable in a browser
- [x] I've checked that all URLs and arguments with special characters are properly quoted or escaped
- [x] I've searched the bugtracker for similar bug reports including closed ones
- [x] I've read bugs section in FAQ


## Verbose log


<!--
Provide the complete verbose output of youtube-dl that clearly demonstrates the problem.
Add the `-v` flag to your command line you run youtube-dl with (`youtube-dl -v <your command line>`), copy the WHOLE output and insert it below. It should look similar to this:
 [debug] System config: []
 [debug] User config: []
 [debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']
 [debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
 [debug] youtube-dl version 2020.07.28
 [debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
 [debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
 [debug] Proxy map: {}
 <more lines>
-->

```
PASTE VERBOSE LOG HERE
```
ubuntu@ip-172-26-9-219:~$ youtube-dl --verbose https://www.eporner.com/hd-porn/HBgBgaViIbY/Busty-Tiny-Teen-With-Angel-Body-Gets-Fucked/
[debug] System config: []
[debug] User config: []
[debug] Custom config: []
[debug] Command-line args: [u'--verbose', u'https://www.eporner.com/hd-porn/HBgBgaViIbY/Busty-Tiny-Teen-With-Angel-Body-Gets-Fucked/']
[debug] Encodings: locale UTF-8, fs UTF-8, out UTF-8, pref UTF-8
[debug] youtube-dl version 2020.07.28
[debug] Python version 2.7.17 (CPython) - Linux-5.3.0-1032-aws-x86_64-with-Ubuntu-18.04-bionic
[debug] exe versions: none
[debug] Proxy map: {}
[Eporner] Busty-Tiny-Teen-With-Angel-Body-Gets-Fucked: Downloading webpage
[Eporner] Busty-Tiny-Teen-With-Angel-Body-Gets-Fucked: Downloading video JSON
WARNING: unable to extract view count; please report this issue on https://yt-dl.org/bug . Make sure you are using the latest version; type  youtube-dl -U  to update. Be sure to call youtube-dl with the --verbose flag and include its complete output.
[debug] Default format spec: best/bestvideo+bestaudio
[debug] Invoking downloader on u'https://cache1-ca-cdn.eporner.com/bb6353b496c613f4904fe9760409625d/5f23b8c504f800/2361178-1080p.mp4'

## Description

<!--
Provide an explanation of your issue 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.
If work on your issue requires account credentials please provide them or explain how one can obtain them.
-->

WRITE DESCRIPTION HERE
Can't download any video from eporner it use YouTube extractor not using eporner.py

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `youtube_dl/extractor/eporner.py`
Content:
```
1 # coding: utf-8
2 from __future__ import unicode_literals
3 
4 import re
5 
6 from .common import InfoExtractor
7 from ..utils import (
8     encode_base_n,
9     ExtractorError,
10     int_or_none,
11     merge_dicts,
12     parse_duration,
13     str_to_int,
14     url_or_none,
15 )
16 
17 
18 class EpornerIE(InfoExtractor):
19     _VALID_URL = r'https?://(?:www\.)?eporner\.com/(?:hd-porn|embed)/(?P<id>\w+)(?:/(?P<display_id>[\w-]+))?'
20     _TESTS = [{
21         'url': 'http://www.eporner.com/hd-porn/95008/Infamous-Tiffany-Teen-Strip-Tease-Video/',
22         'md5': '39d486f046212d8e1b911c52ab4691f8',
23         'info_dict': {
24             'id': 'qlDUmNsj6VS',
25             'display_id': 'Infamous-Tiffany-Teen-Strip-Tease-Video',
26             'ext': 'mp4',
27             'title': 'Infamous Tiffany Teen Strip Tease Video',
28             'description': 'md5:764f39abf932daafa37485eb46efa152',
29             'timestamp': 1232520922,
30             'upload_date': '20090121',
31             'duration': 1838,
32             'view_count': int,
33             'age_limit': 18,
34         },
35         'params': {
36             'proxy': '127.0.0.1:8118'
37         }
38     }, {
39         # New (May 2016) URL layout
40         'url': 'http://www.eporner.com/hd-porn/3YRUtzMcWn0/Star-Wars-XXX-Parody/',
41         'only_matching': True,
42     }, {
43         'url': 'http://www.eporner.com/hd-porn/3YRUtzMcWn0',
44         'only_matching': True,
45     }, {
46         'url': 'http://www.eporner.com/hd-porn/3YRUtzMcWn0',
47         'only_matching': True,
48     }]
49 
50     def _real_extract(self, url):
51         mobj = re.match(self._VALID_URL, url)
52         video_id = mobj.group('id')
53         display_id = mobj.group('display_id') or video_id
54 
55         webpage, urlh = self._download_webpage_handle(url, display_id)
56 
57         video_id = self._match_id(urlh.geturl())
58 
59         hash = self._search_regex(
60             r'hash\s*:\s*["\']([\da-f]{32})', webpage, 'hash')
61 
62         title = self._og_search_title(webpage, default=None) or self._html_search_regex(
63             r'<title>(.+?) - EPORNER', webpage, 'title')
64 
65         # Reverse engineered from vjs.js
66         def calc_hash(s):
67             return ''.join((encode_base_n(int(s[lb:lb + 8], 16), 36) for lb in range(0, 32, 8)))
68 
69         video = self._download_json(
70             'http://www.eporner.com/xhr/video/%s' % video_id,
71             display_id, note='Downloading video JSON',
72             query={
73                 'hash': calc_hash(hash),
74                 'device': 'generic',
75                 'domain': 'www.eporner.com',
76                 'fallback': 'false',
77             })
78 
79         if video.get('available') is False:
80             raise ExtractorError(
81                 '%s said: %s' % (self.IE_NAME, video['message']), expected=True)
82 
83         sources = video['sources']
84 
85         formats = []
86         for kind, formats_dict in sources.items():
87             if not isinstance(formats_dict, dict):
88                 continue
89             for format_id, format_dict in formats_dict.items():
90                 if not isinstance(format_dict, dict):
91                     continue
92                 src = url_or_none(format_dict.get('src'))
93                 if not src or not src.startswith('http'):
94                     continue
95                 if kind == 'hls':
96                     formats.extend(self._extract_m3u8_formats(
97                         src, display_id, 'mp4', entry_protocol='m3u8_native',
98                         m3u8_id=kind, fatal=False))
99                 else:
100                     height = int_or_none(self._search_regex(
101                         r'(\d+)[pP]', format_id, 'height', default=None))
102                     fps = int_or_none(self._search_regex(
103                         r'(\d+)fps', format_id, 'fps', default=None))
104 
105                     formats.append({
106                         'url': src,
107                         'format_id': format_id,
108                         'height': height,
109                         'fps': fps,
110                     })
111         self._sort_formats(formats)
112 
113         json_ld = self._search_json_ld(webpage, display_id, default={})
114 
115         duration = parse_duration(self._html_search_meta(
116             'duration', webpage, default=None))
117         view_count = str_to_int(self._search_regex(
118             r'id="cinemaviews">\s*([0-9,]+)\s*<small>views',
119             webpage, 'view count', fatal=False))
120 
121         return merge_dicts(json_ld, {
122             'id': video_id,
123             'display_id': display_id,
124             'title': title,
125             'duration': duration,
126             'view_count': view_count,
127             'formats': formats,
128             'age_limit': 18,
129         })
130
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/youtube_dl/extractor/eporner.py b/youtube_dl/extractor/eporner.py
--- a/youtube_dl/extractor/eporner.py
+++ b/youtube_dl/extractor/eporner.py
@@ -16,7 +16,7 @@
 
 
 class EpornerIE(InfoExtractor):
-    _VALID_URL = r'https?://(?:www\.)?eporner\.com/(?:hd-porn|embed)/(?P<id>\w+)(?:/(?P<display_id>[\w-]+))?'
+    _VALID_URL = r'https?://(?:www\.)?eporner\.com/(?:(?:hd-porn|embed)/|video-)(?P<id>\w+)(?:/(?P<display_id>[\w-]+))?'
     _TESTS = [{
         'url': 'http://www.eporner.com/hd-porn/95008/Infamous-Tiffany-Teen-Strip-Tease-Video/',
         'md5': '39d486f046212d8e1b911c52ab4691f8',
@@ -45,6 +45,9 @@
     }, {
         'url': 'http://www.eporner.com/hd-porn/3YRUtzMcWn0',
         'only_matching': True,
+    }, {
+        'url': 'https://www.eporner.com/video-FJsA19J3Y3H/one-of-the-greats/',
+        'only_matching': True,
     }]
 
     def _real_extract(self, url):
@@ -57,7 +60,7 @@
         video_id = self._match_id(urlh.geturl())
 
         hash = self._search_regex(
-            r'hash\s*:\s*["\']([\da-f]{32})', webpage, 'hash')
+            r'hash\s*[:=]\s*["\']([\da-f]{32})', webpage, 'hash')
 
         title = self._og_search_title(webpage, default=None) or self._html_search_regex(
             r'<title>(.+?) - EPORNER', webpage, 'title')

{"golden_diff": "diff --git a/youtube_dl/extractor/eporner.py b/youtube_dl/extractor/eporner.py\n--- a/youtube_dl/extractor/eporner.py\n+++ b/youtube_dl/extractor/eporner.py\n@@ -16,7 +16,7 @@\n \n \n class EpornerIE(InfoExtractor):\n-    _VALID_URL = r'https?://(?:www\\.)?eporner\\.com/(?:hd-porn|embed)/(?P<id>\\w+)(?:/(?P<display_id>[\\w-]+))?'\n+    _VALID_URL = r'https?://(?:www\\.)?eporner\\.com/(?:(?:hd-porn|embed)/|video-)(?P<id>\\w+)(?:/(?P<display_id>[\\w-]+))?'\n     _TESTS = [{\n         'url': 'http://www.eporner.com/hd-porn/95008/Infamous-Tiffany-Teen-Strip-Tease-Video/',\n         'md5': '39d486f046212d8e1b911c52ab4691f8',\n@@ -45,6 +45,9 @@\n     }, {\n         'url': 'http://www.eporner.com/hd-porn/3YRUtzMcWn0',\n         'only_matching': True,\n+    }, {\n+        'url': 'https://www.eporner.com/video-FJsA19J3Y3H/one-of-the-greats/',\n+        'only_matching': True,\n     }]\n \n     def _real_extract(self, url):\n@@ -57,7 +60,7 @@\n         video_id = self._match_id(urlh.geturl())\n \n         hash = self._search_regex(\n-            r'hash\\s*:\\s*[\"\\']([\\da-f]{32})', webpage, 'hash')\n+            r'hash\\s*[:=]\\s*[\"\\']([\\da-f]{32})', webpage, 'hash')\n \n         title = self._og_search_title(webpage, default=None) or self._html_search_regex(\n             r'<title>(.+?) - EPORNER', webpage, 'title')\n", "issue": "Eporner stuck at invoked download\n<!--\r\n\r\n######################################################################\r\n  WARNING!\r\n  IGNORING THE FOLLOWING TEMPLATE WILL RESULT IN ISSUE CLOSED AS INCOMPLETE\r\n######################################################################\r\n\r\n-->\r\n\r\n\r\n## Checklist\r\n\r\n<!--\r\nCarefully read and work through this check list in order to prevent the most common mistakes and misuse of youtube-dl:\r\n- First of, make sure you are using the latest version of youtube-dl. Run `youtube-dl --version` and ensure your version is 2020.07.28. If it's not, see https://yt-dl.org/update on how to update. Issues with outdated version will be REJECTED.\r\n- Make sure that all provided video/audio/playlist URLs (if any) are alive and playable in a browser.\r\n- Make sure that all URLs and arguments with special characters are properly quoted or escaped as explained in http://yt-dl.org/escape.\r\n- Search the bugtracker for similar issues: http://yt-dl.org/search-issues. DO NOT post duplicates.\r\n- Read bugs section in FAQ: http://yt-dl.org/reporting\r\n- Finally, put x into all relevant boxes (like this [x])\r\n-->\r\n\r\n- [x] I'm reporting a broken site support issue\r\n- [x] I've verified that I'm running youtube-dl version **2020.07.28**\r\n- [x] I've checked that all provided URLs are alive and playable in a browser\r\n- [x] I've checked that all URLs and arguments with special characters are properly quoted or escaped\r\n- [x] I've searched the bugtracker for similar bug reports including closed ones\r\n- [x] I've read bugs section in FAQ\r\n\r\n\r\n## Verbose log\r\n\r\n\r\n<!--\r\nProvide the complete verbose output of youtube-dl that clearly demonstrates the problem.\r\nAdd the `-v` flag to your command line you run youtube-dl with (`youtube-dl -v <your command line>`), copy the WHOLE output and insert it below. It should look similar to this:\r\n [debug] System config: []\r\n [debug] User config: []\r\n [debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']\r\n [debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251\r\n [debug] youtube-dl version 2020.07.28\r\n [debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2\r\n [debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4\r\n [debug] Proxy map: {}\r\n <more lines>\r\n-->\r\n\r\n```\r\nPASTE VERBOSE LOG HERE\r\n```\r\nubuntu@ip-172-26-9-219:~$ youtube-dl --verbose https://www.eporner.com/hd-porn/HBgBgaViIbY/Busty-Tiny-Teen-With-Angel-Body-Gets-Fucked/\r\n[debug] System config: []\r\n[debug] User config: []\r\n[debug] Custom config: []\r\n[debug] Command-line args: [u'--verbose', u'https://www.eporner.com/hd-porn/HBgBgaViIbY/Busty-Tiny-Teen-With-Angel-Body-Gets-Fucked/']\r\n[debug] Encodings: locale UTF-8, fs UTF-8, out UTF-8, pref UTF-8\r\n[debug] youtube-dl version 2020.07.28\r\n[debug] Python version 2.7.17 (CPython) - Linux-5.3.0-1032-aws-x86_64-with-Ubuntu-18.04-bionic\r\n[debug] exe versions: none\r\n[debug] Proxy map: {}\r\n[Eporner] Busty-Tiny-Teen-With-Angel-Body-Gets-Fucked: Downloading webpage\r\n[Eporner] Busty-Tiny-Teen-With-Angel-Body-Gets-Fucked: Downloading video JSON\r\nWARNING: unable to extract view count; please report this issue on https://yt-dl.org/bug . Make sure you are using the latest version; type  youtube-dl -U  to update. Be sure to call youtube-dl with the --verbose flag and include its complete output.\r\n[debug] Default format spec: best/bestvideo+bestaudio\r\n[debug] Invoking downloader on u'https://cache1-ca-cdn.eporner.com/bb6353b496c613f4904fe9760409625d/5f23b8c504f800/2361178-1080p.mp4'\r\n\r\n## Description\r\n\r\n<!--\r\nProvide an explanation of your issue 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.\r\nIf work on your issue requires account credentials please provide them or explain how one can obtain them.\r\n-->\r\n\r\nWRITE DESCRIPTION HERE\r\nCan't download any video from eporner it use YouTube extractor not using eporner.py\n", "before_files": [{"content": "# coding: utf-8\nfrom __future__ import unicode_literals\n\nimport re\n\nfrom .common import InfoExtractor\nfrom ..utils import (\n    encode_base_n,\n    ExtractorError,\n    int_or_none,\n    merge_dicts,\n    parse_duration,\n    str_to_int,\n    url_or_none,\n)\n\n\nclass EpornerIE(InfoExtractor):\n    _VALID_URL = r'https?://(?:www\\.)?eporner\\.com/(?:hd-porn|embed)/(?P<id>\\w+)(?:/(?P<display_id>[\\w-]+))?'\n    _TESTS = [{\n        'url': 'http://www.eporner.com/hd-porn/95008/Infamous-Tiffany-Teen-Strip-Tease-Video/',\n        'md5': '39d486f046212d8e1b911c52ab4691f8',\n        'info_dict': {\n            'id': 'qlDUmNsj6VS',\n            'display_id': 'Infamous-Tiffany-Teen-Strip-Tease-Video',\n            'ext': 'mp4',\n            'title': 'Infamous Tiffany Teen Strip Tease Video',\n            'description': 'md5:764f39abf932daafa37485eb46efa152',\n            'timestamp': 1232520922,\n            'upload_date': '20090121',\n            'duration': 1838,\n            'view_count': int,\n            'age_limit': 18,\n        },\n        'params': {\n            'proxy': '127.0.0.1:8118'\n        }\n    }, {\n        # New (May 2016) URL layout\n        'url': 'http://www.eporner.com/hd-porn/3YRUtzMcWn0/Star-Wars-XXX-Parody/',\n        'only_matching': True,\n    }, {\n        'url': 'http://www.eporner.com/hd-porn/3YRUtzMcWn0',\n        'only_matching': True,\n    }, {\n        'url': 'http://www.eporner.com/hd-porn/3YRUtzMcWn0',\n        'only_matching': True,\n    }]\n\n    def _real_extract(self, url):\n        mobj = re.match(self._VALID_URL, url)\n        video_id = mobj.group('id')\n        display_id = mobj.group('display_id') or video_id\n\n        webpage, urlh = self._download_webpage_handle(url, display_id)\n\n        video_id = self._match_id(urlh.geturl())\n\n        hash = self._search_regex(\n            r'hash\\s*:\\s*[\"\\']([\\da-f]{32})', webpage, 'hash')\n\n        title = self._og_search_title(webpage, default=None) or self._html_search_regex(\n            r'<title>(.+?) - EPORNER', webpage, 'title')\n\n        # Reverse engineered from vjs.js\n        def calc_hash(s):\n            return ''.join((encode_base_n(int(s[lb:lb + 8], 16), 36) for lb in range(0, 32, 8)))\n\n        video = self._download_json(\n            'http://www.eporner.com/xhr/video/%s' % video_id,\n            display_id, note='Downloading video JSON',\n            query={\n                'hash': calc_hash(hash),\n                'device': 'generic',\n                'domain': 'www.eporner.com',\n                'fallback': 'false',\n            })\n\n        if video.get('available') is False:\n            raise ExtractorError(\n                '%s said: %s' % (self.IE_NAME, video['message']), expected=True)\n\n        sources = video['sources']\n\n        formats = []\n        for kind, formats_dict in sources.items():\n            if not isinstance(formats_dict, dict):\n                continue\n            for format_id, format_dict in formats_dict.items():\n                if not isinstance(format_dict, dict):\n                    continue\n                src = url_or_none(format_dict.get('src'))\n                if not src or not src.startswith('http'):\n                    continue\n                if kind == 'hls':\n                    formats.extend(self._extract_m3u8_formats(\n                        src, display_id, 'mp4', entry_protocol='m3u8_native',\n                        m3u8_id=kind, fatal=False))\n                else:\n                    height = int_or_none(self._search_regex(\n                        r'(\\d+)[pP]', format_id, 'height', default=None))\n                    fps = int_or_none(self._search_regex(\n                        r'(\\d+)fps', format_id, 'fps', default=None))\n\n                    formats.append({\n                        'url': src,\n                        'format_id': format_id,\n                        'height': height,\n                        'fps': fps,\n                    })\n        self._sort_formats(formats)\n\n        json_ld = self._search_json_ld(webpage, display_id, default={})\n\n        duration = parse_duration(self._html_search_meta(\n            'duration', webpage, default=None))\n        view_count = str_to_int(self._search_regex(\n            r'id=\"cinemaviews\">\\s*([0-9,]+)\\s*<small>views',\n            webpage, 'view count', fatal=False))\n\n        return merge_dicts(json_ld, {\n            'id': video_id,\n            'display_id': display_id,\n            'title': title,\n            'duration': duration,\n            'view_count': view_count,\n            'formats': formats,\n            'age_limit': 18,\n        })\n", "path": "youtube_dl/extractor/eporner.py"}], "after_files": [{"content": "# coding: utf-8\nfrom __future__ import unicode_literals\n\nimport re\n\nfrom .common import InfoExtractor\nfrom ..utils import (\n    encode_base_n,\n    ExtractorError,\n    int_or_none,\n    merge_dicts,\n    parse_duration,\n    str_to_int,\n    url_or_none,\n)\n\n\nclass EpornerIE(InfoExtractor):\n    _VALID_URL = r'https?://(?:www\\.)?eporner\\.com/(?:(?:hd-porn|embed)/|video-)(?P<id>\\w+)(?:/(?P<display_id>[\\w-]+))?'\n    _TESTS = [{\n        'url': 'http://www.eporner.com/hd-porn/95008/Infamous-Tiffany-Teen-Strip-Tease-Video/',\n        'md5': '39d486f046212d8e1b911c52ab4691f8',\n        'info_dict': {\n            'id': 'qlDUmNsj6VS',\n            'display_id': 'Infamous-Tiffany-Teen-Strip-Tease-Video',\n            'ext': 'mp4',\n            'title': 'Infamous Tiffany Teen Strip Tease Video',\n            'description': 'md5:764f39abf932daafa37485eb46efa152',\n            'timestamp': 1232520922,\n            'upload_date': '20090121',\n            'duration': 1838,\n            'view_count': int,\n            'age_limit': 18,\n        },\n        'params': {\n            'proxy': '127.0.0.1:8118'\n        }\n    }, {\n        # New (May 2016) URL layout\n        'url': 'http://www.eporner.com/hd-porn/3YRUtzMcWn0/Star-Wars-XXX-Parody/',\n        'only_matching': True,\n    }, {\n        'url': 'http://www.eporner.com/hd-porn/3YRUtzMcWn0',\n        'only_matching': True,\n    }, {\n        'url': 'http://www.eporner.com/hd-porn/3YRUtzMcWn0',\n        'only_matching': True,\n    }, {\n        'url': 'https://www.eporner.com/video-FJsA19J3Y3H/one-of-the-greats/',\n        'only_matching': True,\n    }]\n\n    def _real_extract(self, url):\n        mobj = re.match(self._VALID_URL, url)\n        video_id = mobj.group('id')\n        display_id = mobj.group('display_id') or video_id\n\n        webpage, urlh = self._download_webpage_handle(url, display_id)\n\n        video_id = self._match_id(urlh.geturl())\n\n        hash = self._search_regex(\n            r'hash\\s*[:=]\\s*[\"\\']([\\da-f]{32})', webpage, 'hash')\n\n        title = self._og_search_title(webpage, default=None) or self._html_search_regex(\n            r'<title>(.+?) - EPORNER', webpage, 'title')\n\n        # Reverse engineered from vjs.js\n        def calc_hash(s):\n            return ''.join((encode_base_n(int(s[lb:lb + 8], 16), 36) for lb in range(0, 32, 8)))\n\n        video = self._download_json(\n            'http://www.eporner.com/xhr/video/%s' % video_id,\n            display_id, note='Downloading video JSON',\n            query={\n                'hash': calc_hash(hash),\n                'device': 'generic',\n                'domain': 'www.eporner.com',\n                'fallback': 'false',\n            })\n\n        if video.get('available') is False:\n            raise ExtractorError(\n                '%s said: %s' % (self.IE_NAME, video['message']), expected=True)\n\n        sources = video['sources']\n\n        formats = []\n        for kind, formats_dict in sources.items():\n            if not isinstance(formats_dict, dict):\n                continue\n            for format_id, format_dict in formats_dict.items():\n                if not isinstance(format_dict, dict):\n                    continue\n                src = url_or_none(format_dict.get('src'))\n                if not src or not src.startswith('http'):\n                    continue\n                if kind == 'hls':\n                    formats.extend(self._extract_m3u8_formats(\n                        src, display_id, 'mp4', entry_protocol='m3u8_native',\n                        m3u8_id=kind, fatal=False))\n                else:\n                    height = int_or_none(self._search_regex(\n                        r'(\\d+)[pP]', format_id, 'height', default=None))\n                    fps = int_or_none(self._search_regex(\n                        r'(\\d+)fps', format_id, 'fps', default=None))\n\n                    formats.append({\n                        'url': src,\n                        'format_id': format_id,\n                        'height': height,\n                        'fps': fps,\n                    })\n        self._sort_formats(formats)\n\n        json_ld = self._search_json_ld(webpage, display_id, default={})\n\n        duration = parse_duration(self._html_search_meta(\n            'duration', webpage, default=None))\n        view_count = str_to_int(self._search_regex(\n            r'id=\"cinemaviews\">\\s*([0-9,]+)\\s*<small>views',\n            webpage, 'view count', fatal=False))\n\n        return merge_dicts(json_ld, {\n            'id': video_id,\n            'display_id': display_id,\n            'title': title,\n            'duration': duration,\n            'view_count': view_count,\n            'formats': formats,\n            'age_limit': 18,\n        })\n", "path": "youtube_dl/extractor/eporner.py"}]}