prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  gfycat.com url changes
  - [x] I've **verified** and **I assure** that I'm running youtube-dl **2019.04.17**
  
  ### Before submitting an *issue* make sure you have:
  - [x] At least skimmed through the [README](https://github.com/ytdl-org/youtube-dl/blob/master/README.md), **most notably** the [FAQ](https://github.com/ytdl-org/youtube-dl#faq) and [BUGS](https://github.com/ytdl-org/youtube-dl#bugs) sections
  - [x] [Searched](https://github.com/ytdl-org/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)
  - [x] Site support request (request for adding support for a new site)
  - [ ] Feature request (request for a new functionality)
  - [ ] Question
  - [ ] Other
  
  gfycat.com has added dashes to some urls [https://gfycat.com/acceptablehappygoluckyharborporpoise-baseball](https://gfycat.com/acceptablehappygoluckyharborporpoise-baseball) causing a HTTP Error. 
  This could be fixed by excluding dashes in the url InfoExtractor.
  
  
  
  --- 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             'https://api.gfycat.com/v1/gfycats/%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()
  
  ```
  
golden_diff: 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
  @@ -11,7 +11,7 @@
   
   
   class GfycatIE(InfoExtractor):
  -    _VALID_URL = r'https?://(?:www\.)?gfycat\.com/(?:ifr/|gifs/detail/)?(?P<id>[^/?#]+)'
  +    _VALID_URL = r'https?://(?:www\.)?gfycat\.com/(?:ifr/|gifs/detail/)?(?P<id>[^-/?#]+)'
       _TESTS = [{
           'url': 'http://gfycat.com/DeadlyDecisiveGermanpinscher',
           'info_dict': {
  @@ -47,6 +47,9 @@
       }, {
           'url': 'https://gfycat.com/gifs/detail/UnconsciousLankyIvorygull',
           'only_matching': True
  +    }, {
  +        'url': 'https://gfycat.com/acceptablehappygoluckyharborporpoise-baseball',
  +        'only_matching': True
       }]
   
       def _real_extract(self, url):
  
verification_info: {"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@@ -11,7 +11,7 @@\n \n \n class GfycatIE(InfoExtractor):\n-    _VALID_URL = r'https?://(?:www\\.)?gfycat\\.com/(?:ifr/|gifs/detail/)?(?P<id>[^/?#]+)'\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@@ -47,6 +47,9 @@\n     }, {\n         'url': 'https://gfycat.com/gifs/detail/UnconsciousLankyIvorygull',\n         'only_matching': True\n+    }, {\n+        'url': 'https://gfycat.com/acceptablehappygoluckyharborporpoise-baseball',\n+        'only_matching': True\n     }]\n \n     def _real_extract(self, url):\n", "issue": "gfycat.com url changes\n- [x] I've **verified** and **I assure** that I'm running youtube-dl **2019.04.17**\r\n\r\n### Before submitting an *issue* make sure you have:\r\n- [x] At least skimmed through the [README](https://github.com/ytdl-org/youtube-dl/blob/master/README.md), **most notably** the [FAQ](https://github.com/ytdl-org/youtube-dl#faq) and [BUGS](https://github.com/ytdl-org/youtube-dl#bugs) sections\r\n- [x] [Searched](https://github.com/ytdl-org/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- [x] 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\ngfycat.com has added dashes to some urls [https://gfycat.com/acceptablehappygoluckyharborporpoise-baseball](https://gfycat.com/acceptablehappygoluckyharborporpoise-baseball) causing a HTTP Error. \r\nThis could be fixed by excluding dashes in the url InfoExtractor.\r\n\r\n\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            '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"}], "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        'url': 'https://gfycat.com/acceptablehappygoluckyharborporpoise-baseball',\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"}]}