We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
LinkExtractor is not ignoring .m4v extension (video) by default
By chance I found out that LinkExtractor is not ignoring the video extension m4v in the same way it is ignoring other video formats.

https://en.wikipedia.org/wiki/M4V


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `scrapy/linkextractors/__init__.py`
Content:
```
1 """
2 scrapy.linkextractors
3 
4 This package contains a collection of Link Extractors.
5 
6 For more info see docs/topics/link-extractors.rst
7 """
8 import re
9 
10 from six.moves.urllib.parse import urlparse
11 from parsel.csstranslator import HTMLTranslator
12 from w3lib.url import canonicalize_url
13 
14 from scrapy.utils.misc import arg_to_iter
15 from scrapy.utils.url import (
16     url_is_from_any_domain, url_has_any_extension,
17 )
18 
19 
20 # common file extensions that are not followed if they occur in links
21 IGNORED_EXTENSIONS = [
22     # images
23     'mng', 'pct', 'bmp', 'gif', 'jpg', 'jpeg', 'png', 'pst', 'psp', 'tif',
24     'tiff', 'ai', 'drw', 'dxf', 'eps', 'ps', 'svg',
25 
26     # audio
27     'mp3', 'wma', 'ogg', 'wav', 'ra', 'aac', 'mid', 'au', 'aiff',
28 
29     # video
30     '3gp', 'asf', 'asx', 'avi', 'mov', 'mp4', 'mpg', 'qt', 'rm', 'swf', 'wmv',
31     'm4a',
32 
33     # office suites
34     'xls', 'xlsx', 'ppt', 'pptx', 'pps', 'doc', 'docx', 'odt', 'ods', 'odg',
35     'odp',
36 
37     # other
38     'css', 'pdf', 'exe', 'bin', 'rss', 'zip', 'rar',
39 ]
40 
41 
42 _re_type = type(re.compile("", 0))
43 _matches = lambda url, regexs: any(r.search(url) for r in regexs)
44 _is_valid_url = lambda url: url.split('://', 1)[0] in {'http', 'https', 'file'}
45 
46 
47 class FilteringLinkExtractor(object):
48 
49     _csstranslator = HTMLTranslator()
50 
51     def __init__(self, link_extractor, allow, deny, allow_domains, deny_domains,
52                  restrict_xpaths, canonicalize, deny_extensions, restrict_css):
53 
54         self.link_extractor = link_extractor
55 
56         self.allow_res = [x if isinstance(x, _re_type) else re.compile(x)
57                           for x in arg_to_iter(allow)]
58         self.deny_res = [x if isinstance(x, _re_type) else re.compile(x)
59                          for x in arg_to_iter(deny)]
60 
61         self.allow_domains = set(arg_to_iter(allow_domains))
62         self.deny_domains = set(arg_to_iter(deny_domains))
63 
64         self.restrict_xpaths = tuple(arg_to_iter(restrict_xpaths))
65         self.restrict_xpaths += tuple(map(self._csstranslator.css_to_xpath,
66                                           arg_to_iter(restrict_css)))
67 
68         self.canonicalize = canonicalize
69         if deny_extensions is None:
70             deny_extensions = IGNORED_EXTENSIONS
71         self.deny_extensions = {'.' + e for e in arg_to_iter(deny_extensions)}
72 
73     def _link_allowed(self, link):
74         if not _is_valid_url(link.url):
75             return False
76         if self.allow_res and not _matches(link.url, self.allow_res):
77             return False
78         if self.deny_res and _matches(link.url, self.deny_res):
79             return False
80         parsed_url = urlparse(link.url)
81         if self.allow_domains and not url_is_from_any_domain(parsed_url, self.allow_domains):
82             return False
83         if self.deny_domains and url_is_from_any_domain(parsed_url, self.deny_domains):
84             return False
85         if self.deny_extensions and url_has_any_extension(parsed_url, self.deny_extensions):
86             return False
87         return True
88 
89     def matches(self, url):
90 
91         if self.allow_domains and not url_is_from_any_domain(url, self.allow_domains):
92             return False
93         if self.deny_domains and url_is_from_any_domain(url, self.deny_domains):
94             return False
95 
96         allowed = (regex.search(url) for regex in self.allow_res) if self.allow_res else [True]
97         denied = (regex.search(url) for regex in self.deny_res) if self.deny_res else []
98         return any(allowed) and not any(denied)
99 
100     def _process_links(self, links):
101         links = [x for x in links if self._link_allowed(x)]
102         if self.canonicalize:
103             for link in links:
104                 link.url = canonicalize_url(link.url)
105         links = self.link_extractor._process_links(links)
106         return links
107 
108     def _extract_links(self, *args, **kwargs):
109         return self.link_extractor._extract_links(*args, **kwargs)
110 
111 
112 # Top-level imports
113 from .lxmlhtml import LxmlLinkExtractor as LinkExtractor
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/scrapy/linkextractors/__init__.py b/scrapy/linkextractors/__init__.py
--- a/scrapy/linkextractors/__init__.py
+++ b/scrapy/linkextractors/__init__.py
@@ -28,7 +28,7 @@
 
     # video
     '3gp', 'asf', 'asx', 'avi', 'mov', 'mp4', 'mpg', 'qt', 'rm', 'swf', 'wmv',
-    'm4a',
+    'm4a', 'm4v',
 
     # office suites
     'xls', 'xlsx', 'ppt', 'pptx', 'pps', 'doc', 'docx', 'odt', 'ods', 'odg',

{"golden_diff": "diff --git a/scrapy/linkextractors/__init__.py b/scrapy/linkextractors/__init__.py\n--- a/scrapy/linkextractors/__init__.py\n+++ b/scrapy/linkextractors/__init__.py\n@@ -28,7 +28,7 @@\n \n     # video\n     '3gp', 'asf', 'asx', 'avi', 'mov', 'mp4', 'mpg', 'qt', 'rm', 'swf', 'wmv',\n-    'm4a',\n+    'm4a', 'm4v',\n \n     # office suites\n     'xls', 'xlsx', 'ppt', 'pptx', 'pps', 'doc', 'docx', 'odt', 'ods', 'odg',\n", "issue": "LinkExtractor is not ignoring .m4v extension (video) by default\nBy chance I found out that LinkExtractor is not ignoring the video extension m4v in the same way it is ignoring other video formats.\r\n\r\nhttps://en.wikipedia.org/wiki/M4V\r\n\n", "before_files": [{"content": "\"\"\"\nscrapy.linkextractors\n\nThis package contains a collection of Link Extractors.\n\nFor more info see docs/topics/link-extractors.rst\n\"\"\"\nimport re\n\nfrom six.moves.urllib.parse import urlparse\nfrom parsel.csstranslator import HTMLTranslator\nfrom w3lib.url import canonicalize_url\n\nfrom scrapy.utils.misc import arg_to_iter\nfrom scrapy.utils.url import (\n    url_is_from_any_domain, url_has_any_extension,\n)\n\n\n# common file extensions that are not followed if they occur in links\nIGNORED_EXTENSIONS = [\n    # images\n    'mng', 'pct', 'bmp', 'gif', 'jpg', 'jpeg', 'png', 'pst', 'psp', 'tif',\n    'tiff', 'ai', 'drw', 'dxf', 'eps', 'ps', 'svg',\n\n    # audio\n    'mp3', 'wma', 'ogg', 'wav', 'ra', 'aac', 'mid', 'au', 'aiff',\n\n    # video\n    '3gp', 'asf', 'asx', 'avi', 'mov', 'mp4', 'mpg', 'qt', 'rm', 'swf', 'wmv',\n    'm4a',\n\n    # office suites\n    'xls', 'xlsx', 'ppt', 'pptx', 'pps', 'doc', 'docx', 'odt', 'ods', 'odg',\n    'odp',\n\n    # other\n    'css', 'pdf', 'exe', 'bin', 'rss', 'zip', 'rar',\n]\n\n\n_re_type = type(re.compile(\"\", 0))\n_matches = lambda url, regexs: any(r.search(url) for r in regexs)\n_is_valid_url = lambda url: url.split('://', 1)[0] in {'http', 'https', 'file'}\n\n\nclass FilteringLinkExtractor(object):\n\n    _csstranslator = HTMLTranslator()\n\n    def __init__(self, link_extractor, allow, deny, allow_domains, deny_domains,\n                 restrict_xpaths, canonicalize, deny_extensions, restrict_css):\n\n        self.link_extractor = link_extractor\n\n        self.allow_res = [x if isinstance(x, _re_type) else re.compile(x)\n                          for x in arg_to_iter(allow)]\n        self.deny_res = [x if isinstance(x, _re_type) else re.compile(x)\n                         for x in arg_to_iter(deny)]\n\n        self.allow_domains = set(arg_to_iter(allow_domains))\n        self.deny_domains = set(arg_to_iter(deny_domains))\n\n        self.restrict_xpaths = tuple(arg_to_iter(restrict_xpaths))\n        self.restrict_xpaths += tuple(map(self._csstranslator.css_to_xpath,\n                                          arg_to_iter(restrict_css)))\n\n        self.canonicalize = canonicalize\n        if deny_extensions is None:\n            deny_extensions = IGNORED_EXTENSIONS\n        self.deny_extensions = {'.' + e for e in arg_to_iter(deny_extensions)}\n\n    def _link_allowed(self, link):\n        if not _is_valid_url(link.url):\n            return False\n        if self.allow_res and not _matches(link.url, self.allow_res):\n            return False\n        if self.deny_res and _matches(link.url, self.deny_res):\n            return False\n        parsed_url = urlparse(link.url)\n        if self.allow_domains and not url_is_from_any_domain(parsed_url, self.allow_domains):\n            return False\n        if self.deny_domains and url_is_from_any_domain(parsed_url, self.deny_domains):\n            return False\n        if self.deny_extensions and url_has_any_extension(parsed_url, self.deny_extensions):\n            return False\n        return True\n\n    def matches(self, url):\n\n        if self.allow_domains and not url_is_from_any_domain(url, self.allow_domains):\n            return False\n        if self.deny_domains and url_is_from_any_domain(url, self.deny_domains):\n            return False\n\n        allowed = (regex.search(url) for regex in self.allow_res) if self.allow_res else [True]\n        denied = (regex.search(url) for regex in self.deny_res) if self.deny_res else []\n        return any(allowed) and not any(denied)\n\n    def _process_links(self, links):\n        links = [x for x in links if self._link_allowed(x)]\n        if self.canonicalize:\n            for link in links:\n                link.url = canonicalize_url(link.url)\n        links = self.link_extractor._process_links(links)\n        return links\n\n    def _extract_links(self, *args, **kwargs):\n        return self.link_extractor._extract_links(*args, **kwargs)\n\n\n# Top-level imports\nfrom .lxmlhtml import LxmlLinkExtractor as LinkExtractor\n", "path": "scrapy/linkextractors/__init__.py"}], "after_files": [{"content": "\"\"\"\nscrapy.linkextractors\n\nThis package contains a collection of Link Extractors.\n\nFor more info see docs/topics/link-extractors.rst\n\"\"\"\nimport re\n\nfrom six.moves.urllib.parse import urlparse\nfrom parsel.csstranslator import HTMLTranslator\nfrom w3lib.url import canonicalize_url\n\nfrom scrapy.utils.misc import arg_to_iter\nfrom scrapy.utils.url import (\n    url_is_from_any_domain, url_has_any_extension,\n)\n\n\n# common file extensions that are not followed if they occur in links\nIGNORED_EXTENSIONS = [\n    # images\n    'mng', 'pct', 'bmp', 'gif', 'jpg', 'jpeg', 'png', 'pst', 'psp', 'tif',\n    'tiff', 'ai', 'drw', 'dxf', 'eps', 'ps', 'svg',\n\n    # audio\n    'mp3', 'wma', 'ogg', 'wav', 'ra', 'aac', 'mid', 'au', 'aiff',\n\n    # video\n    '3gp', 'asf', 'asx', 'avi', 'mov', 'mp4', 'mpg', 'qt', 'rm', 'swf', 'wmv',\n    'm4a', 'm4v',\n\n    # office suites\n    'xls', 'xlsx', 'ppt', 'pptx', 'pps', 'doc', 'docx', 'odt', 'ods', 'odg',\n    'odp',\n\n    # other\n    'css', 'pdf', 'exe', 'bin', 'rss', 'zip', 'rar',\n]\n\n\n_re_type = type(re.compile(\"\", 0))\n_matches = lambda url, regexs: any(r.search(url) for r in regexs)\n_is_valid_url = lambda url: url.split('://', 1)[0] in {'http', 'https', 'file'}\n\n\nclass FilteringLinkExtractor(object):\n\n    _csstranslator = HTMLTranslator()\n\n    def __init__(self, link_extractor, allow, deny, allow_domains, deny_domains,\n                 restrict_xpaths, canonicalize, deny_extensions, restrict_css):\n\n        self.link_extractor = link_extractor\n\n        self.allow_res = [x if isinstance(x, _re_type) else re.compile(x)\n                          for x in arg_to_iter(allow)]\n        self.deny_res = [x if isinstance(x, _re_type) else re.compile(x)\n                         for x in arg_to_iter(deny)]\n\n        self.allow_domains = set(arg_to_iter(allow_domains))\n        self.deny_domains = set(arg_to_iter(deny_domains))\n\n        self.restrict_xpaths = tuple(arg_to_iter(restrict_xpaths))\n        self.restrict_xpaths += tuple(map(self._csstranslator.css_to_xpath,\n                                          arg_to_iter(restrict_css)))\n\n        self.canonicalize = canonicalize\n        if deny_extensions is None:\n            deny_extensions = IGNORED_EXTENSIONS\n        self.deny_extensions = {'.' + e for e in arg_to_iter(deny_extensions)}\n\n    def _link_allowed(self, link):\n        if not _is_valid_url(link.url):\n            return False\n        if self.allow_res and not _matches(link.url, self.allow_res):\n            return False\n        if self.deny_res and _matches(link.url, self.deny_res):\n            return False\n        parsed_url = urlparse(link.url)\n        if self.allow_domains and not url_is_from_any_domain(parsed_url, self.allow_domains):\n            return False\n        if self.deny_domains and url_is_from_any_domain(parsed_url, self.deny_domains):\n            return False\n        if self.deny_extensions and url_has_any_extension(parsed_url, self.deny_extensions):\n            return False\n        return True\n\n    def matches(self, url):\n\n        if self.allow_domains and not url_is_from_any_domain(url, self.allow_domains):\n            return False\n        if self.deny_domains and url_is_from_any_domain(url, self.deny_domains):\n            return False\n\n        allowed = (regex.search(url) for regex in self.allow_res) if self.allow_res else [True]\n        denied = (regex.search(url) for regex in self.deny_res) if self.deny_res else []\n        return any(allowed) and not any(denied)\n\n    def _process_links(self, links):\n        links = [x for x in links if self._link_allowed(x)]\n        if self.canonicalize:\n            for link in links:\n                link.url = canonicalize_url(link.url)\n        links = self.link_extractor._process_links(links)\n        return links\n\n    def _extract_links(self, *args, **kwargs):\n        return self.link_extractor._extract_links(*args, **kwargs)\n\n\n# Top-level imports\nfrom .lxmlhtml import LxmlLinkExtractor as LinkExtractor\n", "path": "scrapy/linkextractors/__init__.py"}]}