We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Gfycat cajax json endpoint is gone
### Make sure you are using the *latest* version: run `youtube-dl --version` and ensure your version is *2018.11.23*. If it's not, read [this FAQ entry](https://github.com/rg3/youtube-dl/blob/master/README.md#how-do-i-update-youtube-dl) and update. Issues with outdated version will be rejected.
- [x] I've **verified** and **I assure** that I'm running youtube-dl **2018.11.23**

### Before submitting an *issue* make sure you have:
- [x] At least skimmed through the [README](https://github.com/rg3/youtube-dl/blob/master/README.md), **most notably** the [FAQ](https://github.com/rg3/youtube-dl#faq) and [BUGS](https://github.com/rg3/youtube-dl#bugs) sections
- [x] [Searched](https://github.com/rg3/youtube-dl/search?type=Issues) the bugtracker for similar issues including closed ones
- [x] Checked that provided video/audio/playlist URLs (if any) are alive and playable in a browser

### What is the purpose of your *issue*?
- [x] Bug report (encountered problems with youtube-dl)
- [ ] Site support request (request for adding support for a new site)
- [ ] Feature request (request for a new functionality)
- [ ] Question
- [ ] Other

---

### If the purpose of this *issue* is a *bug report*, *site support request* or you are not completely sure provide the full verbose output as follows:

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 here. It should look similar to one below (replace it with **your** log inserted between triple ```):

```
$ youtube-dl https://gfycat.com/belovedsparseamericanbobtail -v
[debug] System config: []
[debug] User config: []
[debug] Custom config: []
[debug] Command-line args: ['https://gfycat.com/belovedsparseamericanbobtail', '-v']
[debug] Encodings: locale UTF-8, fs utf-8, out UTF-8, pref UTF-8
[debug] youtube-dl version 2018.11.23
[debug] Python version 3.6.5 (CPython) - Darwin-16.7.0-x86_64-i386-64bit
[debug] exe versions: ffmpeg 3.2.2, ffprobe 3.2.2
[debug] Proxy map: {}
[Gfycat] belovedsparseamericanbobtail: Downloading video info
ERROR: Unable to download JSON metadata: HTTP Error 404: Not Found (caused by <HTTPError 404: 'Not Found'>); 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.
  File "/usr/local/bin/youtube-dl/youtube_dl/extractor/common.py", line 605, in _request_webpage
    return self._downloader.urlopen(url_or_request)
  File "/usr/local/bin/youtube-dl/youtube_dl/YoutubeDL.py", line 2211, in urlopen
    return self._opener.open(req, timeout=self._socket_timeout)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 532, in open
    response = meth(req, response)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 642, in http_response
    'http', request, response, code, msg, hdrs)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 564, in error
    result = self._call_chain(*args)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 504, in _call_chain
    result = func(*args)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 756, in http_error_302
    return self.parent.open(new, timeout=req.timeout)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 532, in open
    response = meth(req, response)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 642, in http_response
    'http', request, response, code, msg, hdrs)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 570, in error
    return self._call_chain(*args)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 504, in _call_chain
    result = func(*args)
  File "/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py", line 650, in http_error_default
    raise HTTPError(req.full_url, code, msg, hdrs, fp)

```

---

### Description of your *issue*, suggested solution and other information

Gfycat downloads no longer work because Gfycat removed the API youtube-dl uses:

> Yes we announced deprecation of this endpoint 1.5 years ago. Are you using it for an app still?
>
> This is the link to our current API. https://developers.gfycat.com/api/#introduction
https://www.reddit.com/r/gfycat/comments/a17ewc/embeded_gfycats_returning_failed_to_load_resource/eanbmrh/

So if you wanted to get https://gfycat.com/belovedsparseamericanbobtail then `youtube-dl` would look for the meta at https://gfycat.com/cajax/get/belovedsparseamericanbobtail (you can try the link, it'll 404).
https://github.com/rg3/youtube-dl/blob/d9df8f120b325766181fb474a8c534e51df78f17/youtube_dl/extractor/gfycat.py#L55-L57

It's not obvious how to me how to fix this because the new api uses an oauth2 bearer token, and there isn't a key store AFAIK built into youtube-dl. The closest thing looks like the `.netrc` file support, or possibly a custom [config file entry](https://github.com/rg3/youtube-dl#configuration)

--- 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/gfycat.py`
Content:
```
1 # coding: utf-8
2 from __future__ import unicode_literals
3 
4 from .common import InfoExtractor
5 from ..utils import (
6     int_or_none,
7     float_or_none,
8     qualities,
9     ExtractorError,
10 )
11 
12 
13 class GfycatIE(InfoExtractor):
14     _VALID_URL = r'https?://(?:www\.)?gfycat\.com/(?:ifr/|gifs/detail/)?(?P<id>[^/?#]+)'
15     _TESTS = [{
16         'url': 'http://gfycat.com/DeadlyDecisiveGermanpinscher',
17         'info_dict': {
18             'id': 'DeadlyDecisiveGermanpinscher',
19             'ext': 'mp4',
20             'title': 'Ghost in the Shell',
21             'timestamp': 1410656006,
22             'upload_date': '20140914',
23             'uploader': 'anonymous',
24             'duration': 10.4,
25             'view_count': int,
26             'like_count': int,
27             'dislike_count': int,
28             'categories': list,
29             'age_limit': 0,
30         }
31     }, {
32         'url': 'http://gfycat.com/ifr/JauntyTimelyAmazontreeboa',
33         'info_dict': {
34             'id': 'JauntyTimelyAmazontreeboa',
35             'ext': 'mp4',
36             'title': 'JauntyTimelyAmazontreeboa',
37             'timestamp': 1411720126,
38             'upload_date': '20140926',
39             'uploader': 'anonymous',
40             'duration': 3.52,
41             'view_count': int,
42             'like_count': int,
43             'dislike_count': int,
44             'categories': list,
45             'age_limit': 0,
46         }
47     }, {
48         'url': 'https://gfycat.com/gifs/detail/UnconsciousLankyIvorygull',
49         'only_matching': True
50     }]
51 
52     def _real_extract(self, url):
53         video_id = self._match_id(url)
54 
55         gfy = self._download_json(
56             'http://gfycat.com/cajax/get/%s' % video_id,
57             video_id, 'Downloading video info')
58         if 'error' in gfy:
59             raise ExtractorError('Gfycat said: ' + gfy['error'], expected=True)
60         gfy = gfy['gfyItem']
61 
62         title = gfy.get('title') or gfy['gfyName']
63         description = gfy.get('description')
64         timestamp = int_or_none(gfy.get('createDate'))
65         uploader = gfy.get('userName')
66         view_count = int_or_none(gfy.get('views'))
67         like_count = int_or_none(gfy.get('likes'))
68         dislike_count = int_or_none(gfy.get('dislikes'))
69         age_limit = 18 if gfy.get('nsfw') == '1' else 0
70 
71         width = int_or_none(gfy.get('width'))
72         height = int_or_none(gfy.get('height'))
73         fps = int_or_none(gfy.get('frameRate'))
74         num_frames = int_or_none(gfy.get('numFrames'))
75 
76         duration = float_or_none(num_frames, fps) if num_frames and fps else None
77 
78         categories = gfy.get('tags') or gfy.get('extraLemmas') or []
79 
80         FORMATS = ('gif', 'webm', 'mp4')
81         quality = qualities(FORMATS)
82 
83         formats = []
84         for format_id in FORMATS:
85             video_url = gfy.get('%sUrl' % format_id)
86             if not video_url:
87                 continue
88             filesize = int_or_none(gfy.get('%sSize' % format_id))
89             formats.append({
90                 'url': video_url,
91                 'format_id': format_id,
92                 'width': width,
93                 'height': height,
94                 'fps': fps,
95                 'filesize': filesize,
96                 'quality': quality(format_id),
97             })
98         self._sort_formats(formats)
99 
100         return {
101             'id': video_id,
102             'title': title,
103             'description': description,
104             'timestamp': timestamp,
105             'uploader': uploader,
106             'duration': duration,
107             'view_count': view_count,
108             'like_count': like_count,
109             'dislike_count': dislike_count,
110             'categories': categories,
111             'age_limit': age_limit,
112             'formats': formats,
113         }
114
```
--- 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/gfycat.py b/youtube_dl/extractor/gfycat.py
--- a/youtube_dl/extractor/gfycat.py
+++ b/youtube_dl/extractor/gfycat.py
@@ -53,7 +53,7 @@
         video_id = self._match_id(url)
 
         gfy = self._download_json(
-            'http://gfycat.com/cajax/get/%s' % video_id,
+            'https://api.gfycat.com/v1/gfycats/%s' % video_id,
             video_id, 'Downloading video info')
         if 'error' in gfy:
             raise ExtractorError('Gfycat said: ' + gfy['error'], expected=True)

{"golden_diff": "diff --git a/youtube_dl/extractor/gfycat.py b/youtube_dl/extractor/gfycat.py\n--- a/youtube_dl/extractor/gfycat.py\n+++ b/youtube_dl/extractor/gfycat.py\n@@ -53,7 +53,7 @@\n         video_id = self._match_id(url)\n \n         gfy = self._download_json(\n-            'http://gfycat.com/cajax/get/%s' % video_id,\n+            'https://api.gfycat.com/v1/gfycats/%s' % video_id,\n             video_id, 'Downloading video info')\n         if 'error' in gfy:\n             raise ExtractorError('Gfycat said: ' + gfy['error'], expected=True)\n", "issue": "Gfycat cajax json endpoint is gone\n### Make sure you are using the *latest* version: run `youtube-dl --version` and ensure your version is *2018.11.23*. If it's not, read [this FAQ entry](https://github.com/rg3/youtube-dl/blob/master/README.md#how-do-i-update-youtube-dl) and update. Issues with outdated version will be rejected.\r\n- [x] I've **verified** and **I assure** that I'm running youtube-dl **2018.11.23**\r\n\r\n### Before submitting an *issue* make sure you have:\r\n- [x] At least skimmed through the [README](https://github.com/rg3/youtube-dl/blob/master/README.md), **most notably** the [FAQ](https://github.com/rg3/youtube-dl#faq) and [BUGS](https://github.com/rg3/youtube-dl#bugs) sections\r\n- [x] [Searched](https://github.com/rg3/youtube-dl/search?type=Issues) the bugtracker for similar issues including closed ones\r\n- [x] Checked that provided video/audio/playlist URLs (if any) are alive and playable in a browser\r\n\r\n### What is the purpose of your *issue*?\r\n- [x] Bug report (encountered problems with youtube-dl)\r\n- [ ] Site support request (request for adding support for a new site)\r\n- [ ] Feature request (request for a new functionality)\r\n- [ ] Question\r\n- [ ] Other\r\n\r\n---\r\n\r\n### If the purpose of this *issue* is a *bug report*, *site support request* or you are not completely sure provide the full verbose output as follows:\r\n\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 here. It should look similar to one below (replace it with **your** log inserted between triple ```):\r\n\r\n```\r\n$ youtube-dl https://gfycat.com/belovedsparseamericanbobtail -v\r\n[debug] System config: []\r\n[debug] User config: []\r\n[debug] Custom config: []\r\n[debug] Command-line args: ['https://gfycat.com/belovedsparseamericanbobtail', '-v']\r\n[debug] Encodings: locale UTF-8, fs utf-8, out UTF-8, pref UTF-8\r\n[debug] youtube-dl version 2018.11.23\r\n[debug] Python version 3.6.5 (CPython) - Darwin-16.7.0-x86_64-i386-64bit\r\n[debug] exe versions: ffmpeg 3.2.2, ffprobe 3.2.2\r\n[debug] Proxy map: {}\r\n[Gfycat] belovedsparseamericanbobtail: Downloading video info\r\nERROR: Unable to download JSON metadata: HTTP Error 404: Not Found (caused by <HTTPError 404: 'Not Found'>); 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  File \"/usr/local/bin/youtube-dl/youtube_dl/extractor/common.py\", line 605, in _request_webpage\r\n    return self._downloader.urlopen(url_or_request)\r\n  File \"/usr/local/bin/youtube-dl/youtube_dl/YoutubeDL.py\", line 2211, in urlopen\r\n    return self._opener.open(req, timeout=self._socket_timeout)\r\n  File \"/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py\", line 532, in open\r\n    response = meth(req, response)\r\n  File \"/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py\", line 642, in http_response\r\n    'http', request, response, code, msg, hdrs)\r\n  File \"/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py\", line 564, in error\r\n    result = self._call_chain(*args)\r\n  File \"/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py\", line 504, in _call_chain\r\n    result = func(*args)\r\n  File \"/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py\", line 756, in http_error_302\r\n    return self.parent.open(new, timeout=req.timeout)\r\n  File \"/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py\", line 532, in open\r\n    response = meth(req, response)\r\n  File \"/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py\", line 642, in http_response\r\n    'http', request, response, code, msg, hdrs)\r\n  File \"/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py\", line 570, in error\r\n    return self._call_chain(*args)\r\n  File \"/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py\", line 504, in _call_chain\r\n    result = func(*args)\r\n  File \"/usr/local/Cellar/python/3.6.5/Frameworks/Python.framework/Versions/3.6/lib/python3.6/urllib/request.py\", line 650, in http_error_default\r\n    raise HTTPError(req.full_url, code, msg, hdrs, fp)\r\n\r\n```\r\n\r\n---\r\n\r\n### Description of your *issue*, suggested solution and other information\r\n\r\nGfycat downloads no longer work because Gfycat removed the API youtube-dl uses:\r\n\r\n> Yes we announced deprecation of this endpoint 1.5 years ago. Are you using it for an app still?\r\n>\r\n> This is the link to our current API. https://developers.gfycat.com/api/#introduction\r\nhttps://www.reddit.com/r/gfycat/comments/a17ewc/embeded_gfycats_returning_failed_to_load_resource/eanbmrh/\r\n\r\nSo if you wanted to get https://gfycat.com/belovedsparseamericanbobtail then `youtube-dl` would look for the meta at https://gfycat.com/cajax/get/belovedsparseamericanbobtail (you can try the link, it'll 404).\r\nhttps://github.com/rg3/youtube-dl/blob/d9df8f120b325766181fb474a8c534e51df78f17/youtube_dl/extractor/gfycat.py#L55-L57\r\n\r\nIt's not obvious how to me how to fix this because the new api uses an oauth2 bearer token, and there isn't a key store AFAIK built into youtube-dl. The closest thing looks like the `.netrc` file support, or possibly a custom [config file entry](https://github.com/rg3/youtube-dl#configuration)\n", "before_files": [{"content": "# coding: utf-8\nfrom __future__ import unicode_literals\n\nfrom .common import InfoExtractor\nfrom ..utils import (\n    int_or_none,\n    float_or_none,\n    qualities,\n    ExtractorError,\n)\n\n\nclass GfycatIE(InfoExtractor):\n    _VALID_URL = r'https?://(?:www\\.)?gfycat\\.com/(?:ifr/|gifs/detail/)?(?P<id>[^/?#]+)'\n    _TESTS = [{\n        'url': 'http://gfycat.com/DeadlyDecisiveGermanpinscher',\n        'info_dict': {\n            'id': 'DeadlyDecisiveGermanpinscher',\n            'ext': 'mp4',\n            'title': 'Ghost in the Shell',\n            'timestamp': 1410656006,\n            'upload_date': '20140914',\n            'uploader': 'anonymous',\n            'duration': 10.4,\n            'view_count': int,\n            'like_count': int,\n            'dislike_count': int,\n            'categories': list,\n            'age_limit': 0,\n        }\n    }, {\n        'url': 'http://gfycat.com/ifr/JauntyTimelyAmazontreeboa',\n        'info_dict': {\n            'id': 'JauntyTimelyAmazontreeboa',\n            'ext': 'mp4',\n            'title': 'JauntyTimelyAmazontreeboa',\n            'timestamp': 1411720126,\n            'upload_date': '20140926',\n            'uploader': 'anonymous',\n            'duration': 3.52,\n            'view_count': int,\n            'like_count': int,\n            'dislike_count': int,\n            'categories': list,\n            'age_limit': 0,\n        }\n    }, {\n        'url': 'https://gfycat.com/gifs/detail/UnconsciousLankyIvorygull',\n        'only_matching': True\n    }]\n\n    def _real_extract(self, url):\n        video_id = self._match_id(url)\n\n        gfy = self._download_json(\n            'http://gfycat.com/cajax/get/%s' % video_id,\n            video_id, 'Downloading video info')\n        if 'error' in gfy:\n            raise ExtractorError('Gfycat said: ' + gfy['error'], expected=True)\n        gfy = gfy['gfyItem']\n\n        title = gfy.get('title') or gfy['gfyName']\n        description = gfy.get('description')\n        timestamp = int_or_none(gfy.get('createDate'))\n        uploader = gfy.get('userName')\n        view_count = int_or_none(gfy.get('views'))\n        like_count = int_or_none(gfy.get('likes'))\n        dislike_count = int_or_none(gfy.get('dislikes'))\n        age_limit = 18 if gfy.get('nsfw') == '1' else 0\n\n        width = int_or_none(gfy.get('width'))\n        height = int_or_none(gfy.get('height'))\n        fps = int_or_none(gfy.get('frameRate'))\n        num_frames = int_or_none(gfy.get('numFrames'))\n\n        duration = float_or_none(num_frames, fps) if num_frames and fps else None\n\n        categories = gfy.get('tags') or gfy.get('extraLemmas') or []\n\n        FORMATS = ('gif', 'webm', 'mp4')\n        quality = qualities(FORMATS)\n\n        formats = []\n        for format_id in FORMATS:\n            video_url = gfy.get('%sUrl' % format_id)\n            if not video_url:\n                continue\n            filesize = int_or_none(gfy.get('%sSize' % format_id))\n            formats.append({\n                'url': video_url,\n                'format_id': format_id,\n                'width': width,\n                'height': height,\n                'fps': fps,\n                'filesize': filesize,\n                'quality': quality(format_id),\n            })\n        self._sort_formats(formats)\n\n        return {\n            'id': video_id,\n            'title': title,\n            'description': description,\n            'timestamp': timestamp,\n            'uploader': uploader,\n            'duration': duration,\n            'view_count': view_count,\n            'like_count': like_count,\n            'dislike_count': dislike_count,\n            'categories': categories,\n            'age_limit': age_limit,\n            'formats': formats,\n        }\n", "path": "youtube_dl/extractor/gfycat.py"}], "after_files": [{"content": "# coding: utf-8\nfrom __future__ import unicode_literals\n\nfrom .common import InfoExtractor\nfrom ..utils import (\n    int_or_none,\n    float_or_none,\n    qualities,\n    ExtractorError,\n)\n\n\nclass GfycatIE(InfoExtractor):\n    _VALID_URL = r'https?://(?:www\\.)?gfycat\\.com/(?:ifr/|gifs/detail/)?(?P<id>[^/?#]+)'\n    _TESTS = [{\n        'url': 'http://gfycat.com/DeadlyDecisiveGermanpinscher',\n        'info_dict': {\n            'id': 'DeadlyDecisiveGermanpinscher',\n            'ext': 'mp4',\n            'title': 'Ghost in the Shell',\n            'timestamp': 1410656006,\n            'upload_date': '20140914',\n            'uploader': 'anonymous',\n            'duration': 10.4,\n            'view_count': int,\n            'like_count': int,\n            'dislike_count': int,\n            'categories': list,\n            'age_limit': 0,\n        }\n    }, {\n        'url': 'http://gfycat.com/ifr/JauntyTimelyAmazontreeboa',\n        'info_dict': {\n            'id': 'JauntyTimelyAmazontreeboa',\n            'ext': 'mp4',\n            'title': 'JauntyTimelyAmazontreeboa',\n            'timestamp': 1411720126,\n            'upload_date': '20140926',\n            'uploader': 'anonymous',\n            'duration': 3.52,\n            'view_count': int,\n            'like_count': int,\n            'dislike_count': int,\n            'categories': list,\n            'age_limit': 0,\n        }\n    }, {\n        'url': 'https://gfycat.com/gifs/detail/UnconsciousLankyIvorygull',\n        'only_matching': True\n    }]\n\n    def _real_extract(self, url):\n        video_id = self._match_id(url)\n\n        gfy = self._download_json(\n            'https://api.gfycat.com/v1/gfycats/%s' % video_id,\n            video_id, 'Downloading video info')\n        if 'error' in gfy:\n            raise ExtractorError('Gfycat said: ' + gfy['error'], expected=True)\n        gfy = gfy['gfyItem']\n\n        title = gfy.get('title') or gfy['gfyName']\n        description = gfy.get('description')\n        timestamp = int_or_none(gfy.get('createDate'))\n        uploader = gfy.get('userName')\n        view_count = int_or_none(gfy.get('views'))\n        like_count = int_or_none(gfy.get('likes'))\n        dislike_count = int_or_none(gfy.get('dislikes'))\n        age_limit = 18 if gfy.get('nsfw') == '1' else 0\n\n        width = int_or_none(gfy.get('width'))\n        height = int_or_none(gfy.get('height'))\n        fps = int_or_none(gfy.get('frameRate'))\n        num_frames = int_or_none(gfy.get('numFrames'))\n\n        duration = float_or_none(num_frames, fps) if num_frames and fps else None\n\n        categories = gfy.get('tags') or gfy.get('extraLemmas') or []\n\n        FORMATS = ('gif', 'webm', 'mp4')\n        quality = qualities(FORMATS)\n\n        formats = []\n        for format_id in FORMATS:\n            video_url = gfy.get('%sUrl' % format_id)\n            if not video_url:\n                continue\n            filesize = int_or_none(gfy.get('%sSize' % format_id))\n            formats.append({\n                'url': video_url,\n                'format_id': format_id,\n                'width': width,\n                'height': height,\n                'fps': fps,\n                'filesize': filesize,\n                'quality': quality(format_id),\n            })\n        self._sort_formats(formats)\n\n        return {\n            'id': video_id,\n            'title': title,\n            'description': description,\n            'timestamp': timestamp,\n            'uploader': uploader,\n            'duration': duration,\n            'view_count': view_count,\n            'like_count': like_count,\n            'dislike_count': dislike_count,\n            'categories': categories,\n            'age_limit': age_limit,\n            'formats': formats,\n        }\n", "path": "youtube_dl/extractor/gfycat.py"}]}