Repository: streamlink/streamlink

Issue:
plugins.youtube: fix url check
valid url example:
https://www.youtube.com/c/ТелеканалНАШ


Discussion:
# [Codecov](https://codecov.io/gh/streamlink/streamlink/pull/2557?src=pr&el=h1) Report
> Merging [#2557](https://codecov.io/gh/streamlink/streamlink/pull/2557?src=pr&el=desc) into [master](https://codecov.io/gh/streamlink/streamlink/commit/0f01f35a6356595f42cf8ab0f1f4a282b41cbbe6?src=pr&el=desc) will **decrease** coverage by `1.07%`.
> The diff coverage is `n/a`.


```diff
@@            Coverage Diff             @@
##           master    #2557      +/-   ##
==========================================
- Coverage   52.54%   51.46%   -1.08%     
==========================================
  Files         239      239              
  Lines       15131    14797     -334     
==========================================
- Hits         7950     7616     -334     
  Misses       7181     7181
```


Resolving patch:
diff --git a/src/streamlink/plugins/youtube.py b/src/streamlink/plugins/youtube.py
--- a/src/streamlink/plugins/youtube.py
+++ b/src/streamlink/plugins/youtube.py
@@ -85,8 +85,13 @@ def parse_fmt_list(formatsmap):
                 },
                 validate.optional("videoDetails"): {
                     validate.optional("isLive"): validate.transform(bool),
-                }
-            }
+                },
+                validate.optional("playabilityStatus"): {
+                    validate.optional("status"): validate.text,
+                    validate.optional("reason"): validate.all(validate.text,
+                                                              validate.transform(maybe_decode)),
+                },
+            },
         ),
         validate.optional("live_playback"): validate.transform(bool),
         validate.optional("reason"): validate.all(validate.text, validate.transform(maybe_decode)),
@@ -104,20 +109,25 @@ def parse_fmt_list(formatsmap):
 _url_re = re.compile(r"""(?x)https?://(?:\w+\.)?youtube\.com
     (?:
         (?:
-            /(?:watch.+v=|embed/(?!live_stream)|v/)
-            (?P<video_id>[0-9A-z_-]{11})
+            /(?:
+                watch.+v=
+                |
+                embed/(?!live_stream)
+                |
+                v/
+            )(?P<video_id>[0-9A-z_-]{11})
         )
         |
         (?:
             /(?:
-                (?:user|channel)/
+                (?:user|c(?:hannel)?)/
                 |
                 embed/live_stream\?channel=
-            )(?P<user>[^/?&]+)
+            )[^/?&]+
         )
         |
         (?:
-            /(?:c/)?(?P<liveChannel>[^/?]+)/live/?$
+            /(?:c/)?[^/?]+/live/?$
         )
     )
 """)
@@ -316,9 +326,12 @@ def _get_stream_info(self, video_id):
 
             res = self.session.http.get(self._video_info_url, params=params)
             info_parsed = parse_query(res.content if is_py2 else res.text, name="config", schema=_config_schema)
-            if info_parsed.get("status") == "fail":
+            if (info_parsed.get("player_response", {}).get("playabilityStatus", {}).get("status") != "OK"
+                    or info_parsed.get("status") == "fail"):
+                reason = (info_parsed.get("player_response", {}).get("playabilityStatus", {}).get("reason")
+                          or info_parsed.get("reason"))
                 log.debug("get_video_info - {0}: {1}".format(
-                    count, info_parsed.get("reason"))
+                    count, reason)
                 )
                 continue
             self.author = info_parsed.get("author")


Test patch:
diff --git a/tests/plugins/test_youtube.py b/tests/plugins/test_youtube.py
--- a/tests/plugins/test_youtube.py
+++ b/tests/plugins/test_youtube.py
@@ -6,53 +6,39 @@
 class TestPluginYouTube(unittest.TestCase):
     def test_can_handle_url(self):
         should_match = [
+            "https://www.youtube.com/EXAMPLE/live",
+            "https://www.youtube.com/c/EXAMPLE",
+            "https://www.youtube.com/c/EXAMPLE/",
             "https://www.youtube.com/c/EXAMPLE/live",
             "https://www.youtube.com/c/EXAMPLE/live/",
             "https://www.youtube.com/channel/EXAMPLE",
-            "https://www.youtube.com/v/aqz-KE-bpKQ",
+            "https://www.youtube.com/channel/EXAMPLE/",
             "https://www.youtube.com/embed/aqz-KE-bpKQ",
+            "https://www.youtube.com/embed/live_stream?channel=UCNye-wNBqNL5ZzHSJj3l8Bg",
+            "https://www.youtube.com/user/EXAMPLE",
             "https://www.youtube.com/user/EXAMPLE/",
+            "https://www.youtube.com/user/EXAMPLE/live",
+            "https://www.youtube.com/v/aqz-KE-bpKQ",
             "https://www.youtube.com/watch?v=aqz-KE-bpKQ",
-            "https://www.youtube.com/embed/live_stream?channel=UCNye-wNBqNL5ZzHSJj3l8Bg",
         ]
         for url in should_match:
-            self.assertTrue(YouTube.can_handle_url(url))
+            self.assertTrue(YouTube.can_handle_url(url), url)
 
         should_not_match = [
+            "https://accounts.google.com/",
             "https://www.youtube.com",
+            "https://www.youtube.com/account",
+            "https://www.youtube.com/feed/guide_builder",
+            "https://www.youtube.com/t/terms",
         ]
         for url in should_not_match:
-            self.assertFalse(YouTube.can_handle_url(url))
+            self.assertFalse(YouTube.can_handle_url(url), url)
 
     def _test_regex(self, url, expected_string, expected_group):
         m = _url_re.match(url)
         self.assertIsNotNone(m)
         self.assertEqual(expected_string, m.group(expected_group))
 
-    def test_regex_liveChannel_c(self):
-        self._test_regex("https://www.youtube.com/c/EXAMPLE/live",
-                         "EXAMPLE", "liveChannel")
-
-    def test_regex_liveChannel_no_c(self):
-        self._test_regex("https://www.youtube.com/EXAMPLE1/live",
-                         "EXAMPLE1", "liveChannel")
-
-    def test_regex_user_channel(self):
-        self._test_regex("https://www.youtube.com/channel/EXAMPLE2",
-                         "EXAMPLE2", "user")
-
-    def test_regex_user_user(self):
-        self._test_regex("https://www.youtube.com/channel/EXAMPLE3",
-                         "EXAMPLE3", "user")
-
-    def test_regex_user_embed_list_stream(self):
-        self._test_regex("https://www.youtube.com/embed/live_stream?channel=UCNye-wNBqNL5ZzHSJj3l8Bg",
-                         "UCNye-wNBqNL5ZzHSJj3l8Bg", "user")
-
-    def test_regex_user_embed_list_stream_2(self):
-        self._test_regex("https://www.youtube.com/embed/live_stream?channel=UCNye-wNBqNL5ZzHSJj3l8Bg&autoplay=1&modestbranding=1&rel=0&showinfo=0&color=white&fs=1",
-                         "UCNye-wNBqNL5ZzHSJj3l8Bg", "user")
-
     def test_regex_video_id_v(self):
         self._test_regex("https://www.youtube.com/v/aqz-KE-bpKQ",
                          "aqz-KE-bpKQ", "video_id")