Repository: streamlink/streamlink

Issue:
plugins.youtube: Could not find videoId on channel page but there's a live-stream available
### Checklist

- [X] This is a [plugin issue](https://streamlink.github.io/plugins.html) and not [a different kind of issue](https://github.com/streamlink/streamlink/issues/new/choose)
- [X] [I have read the contribution guidelines](https://github.com/streamlink/streamlink/blob/master/CONTRIBUTING.md#contributing-to-streamlink)
- [X] [I have checked the list of open and recently closed plugin issues](https://github.com/streamlink/streamlink/issues?q=is%3Aissue+label%3A%22plugin+issue%22)
- [X] [I have checked the commit log of the master branch](https://github.com/streamlink/streamlink/commits/master)

### Streamlink version

streamlink 6.3.1

### Description

I've been getting the following error since yesterday on multiple youtube channels that actually have at least one live-stream available but the plugin seems to be unable to find it:

```
[plugins.youtube][error] Could not find videoId on channel page
```

Here's a non-exhaustive list of channels that I've been able to reproduce this error:

- https://www.youtube.com/@ABCNews
- https://www.youtube.com/user/ABCNews
- https://www.youtube.com/@lanacion (added to the debug log)
- https://www.youtube.com/user/LaNacionTV 
- https://www.youtube.com/@LofiGirl (added to the debug log)
- https://www.youtube.com/@France24_en

Please check the debug log for details.

Of note, there are a few channels that continue to work just fine, namely:

- https://www.youtube.com/@jazzbossacollection7548
- https://www.youtube.com/@recordnews (added to the debug log)

### Debug log

```text
streamlink --loglevel debug https://www.youtube.com/@LofiGirl

[cli][debug] OS:         Linux-6.1.0-13-amd64-x86_64-with-glibc2.36
[cli][debug] Python:     3.11.2
[cli][debug] OpenSSL:    OpenSSL 3.0.11 19 Sep 2023
[cli][debug] Streamlink: 6.3.1
[cli][debug] Dependencies:
[cli][debug]  certifi: 2022.9.24
[cli][debug]  isodate: 0.6.1
[cli][debug]  lxml: 4.9.2
[cli][debug]  pycountry: 22.3.5
[cli][debug]  pycryptodome: 3.18.0
[cli][debug]  PySocks: 1.7.1
[cli][debug]  requests: 2.28.1
[cli][debug]  trio: 0.22.2
[cli][debug]  trio-websocket: 0.10.3
[cli][debug]  typing-extensions: 4.7.1
[cli][debug]  urllib3: 1.26.12
[cli][debug]  websocket-client: 1.6.4
[cli][debug] Arguments:
[cli][debug]  url=https://www.youtube.com/@LofiGirl
[cli][debug]  --loglevel=debug
[cli][info] Found matching plugin youtube for URL https://www.youtube.com/@LofiGirl
[plugins.youtube][error] Could not find videoId on channel page
error: No playable streams found on this URL: https://www.youtube.com/@LofiGirl

---

streamlink --loglevel debug https://www.youtube.com/@lanacion

[cli][debug] OS:         Linux-6.1.0-13-amd64-x86_64-with-glibc2.36
[cli][debug] Python:     3.11.2
[cli][debug] OpenSSL:    OpenSSL 3.0.11 19 Sep 2023
[cli][debug] Streamlink: 6.3.1
[cli][debug] Dependencies:
[cli][debug]  certifi: 2022.9.24
[cli][debug]  isodate: 0.6.1
[cli][debug]  lxml: 4.9.2
[cli][debug]  pycountry: 22.3.5
[cli][debug]  pycryptodome: 3.18.0
[cli][debug]  PySocks: 1.7.1
[cli][debug]  requests: 2.28.1
[cli][debug]  trio: 0.22.2
[cli][debug]  trio-websocket: 0.10.3
[cli][debug]  typing-extensions: 4.7.1
[cli][debug]  urllib3: 1.26.12
[cli][debug]  websocket-client: 1.6.4
[cli][debug] Arguments:
[cli][debug]  url=https://www.youtube.com/@lanacion
[cli][debug]  --loglevel=debug
[cli][info] Found matching plugin youtube for URL https://www.youtube.com/@lanacion
[plugins.youtube][error] Could not find videoId on channel page
error: No playable streams found on this URL: https://www.youtube.com/@lanacion

---

streamlink --loglevel debug https://www.youtube.com/@recordnews

[cli][debug] OS:         Linux-6.1.0-13-amd64-x86_64-with-glibc2.36
[cli][debug] Python:     3.11.2
[cli][debug] OpenSSL:    OpenSSL 3.0.11 19 Sep 2023
[cli][debug] Streamlink: 6.3.1
[cli][debug] Dependencies:
[cli][debug]  certifi: 2022.9.24
[cli][debug]  isodate: 0.6.1
[cli][debug]  lxml: 4.9.2
[cli][debug]  pycountry: 22.3.5
[cli][debug]  pycryptodome: 3.18.0
[cli][debug]  PySocks: 1.7.1
[cli][debug]  requests: 2.28.1
[cli][debug]  trio: 0.22.2
[cli][debug]  trio-websocket: 0.10.3
[cli][debug]  typing-extensions: 4.7.1
[cli][debug]  urllib3: 1.26.12
[cli][debug]  websocket-client: 1.6.4
[cli][debug] Arguments:
[cli][debug]  url=https://www.youtube.com/@recordnews
[cli][debug]  --loglevel=debug
[cli][info] Found matching plugin youtube for URL https://www.youtube.com/@recordnews
[plugins.youtube][debug] Using video ID: QSGgKI9N9Mk
[plugins.youtube][debug] This video is live.
[utils.l10n][debug] Language code: en_US
Available streams: 144p (worst), 240p, 360p, 480p, 720p, 1080p (best)
```



Discussion:
#5434

The `ytInitialData` JSON format has once again changed...

This should fix it, but I will have to make further tests:

```diff
diff --git a/src/streamlink/plugins/youtube.py b/src/streamlink/plugins/youtube.py
index a85290c5..9824f16b 100644
--- a/src/streamlink/plugins/youtube.py
+++ b/src/streamlink/plugins/youtube.py
@@ -335,8 +335,10 @@ class YouTube(Plugin):
 
     @staticmethod
     def _data_video_id(data):
-        if data:
-            for videoRenderer in search_dict(data, "videoRenderer"):
+        if not data:
+            return None
+        for key in ("videoRenderer", "gridVideoRenderer"):
+            for videoRenderer in search_dict(data, key):
                 videoId = videoRenderer.get("videoId")
                 if videoId is not None:
                     return videoId
```

```
$ streamlink -l debug https://www.youtube.com/@LofiGirl
[cli][debug] OS:         Linux-6.6.1-1-git-x86_64-with-glibc2.38
[cli][debug] Python:     3.11.5
[cli][debug] OpenSSL:    OpenSSL 3.1.4 24 Oct 2023
[cli][debug] Streamlink: 6.3.1+25.gd8e677bc.dirty
[cli][debug] Dependencies:
[cli][debug]  certifi: 2023.7.22
[cli][debug]  isodate: 0.6.1
[cli][debug]  lxml: 4.9.3
[cli][debug]  pycountry: 22.3.5
[cli][debug]  pycryptodome: 3.19.0
[cli][debug]  PySocks: 1.7.1
[cli][debug]  requests: 2.31.0
[cli][debug]  trio: 0.22.2
[cli][debug]  trio-websocket: 0.11.1
[cli][debug]  typing-extensions: 4.8.0
[cli][debug]  urllib3: 2.0.6
[cli][debug]  websocket-client: 1.6.4
[cli][debug] Arguments:
[cli][debug]  url=https://www.youtube.com/@LofiGirl
[cli][debug]  --loglevel=debug
[cli][debug]  --player=mpv
[cli][info] Found matching plugin youtube for URL https://www.youtube.com/@LofiGirl
[plugins.youtube][debug] consent target: https://consent.youtube.com/save
[plugins.youtube][debug] consent data: gl, m, app, pc, continue, x, bl, hl, src, cm, set_ytc, set_apyt, set_eom
[plugins.youtube][debug] Using video ID: jfKfPfyJRdk
[plugins.youtube][debug] This video is live.
[utils.l10n][debug] Language code: en_US
Available streams: 144p (worst), 240p, 360p, 480p, 720p, 1080p (best)
```

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
@@ -335,8 +335,10 @@ def _get_data_from_api(self, res):
 
     @staticmethod
     def _data_video_id(data):
-        if data:
-            for videoRenderer in search_dict(data, "videoRenderer"):
+        if not data:
+            return None
+        for key in ("videoRenderer", "gridVideoRenderer"):
+            for videoRenderer in search_dict(data, key):
                 videoId = videoRenderer.get("videoId")
                 if videoId is not None:
                     return videoId


Test patch: