Repository: streamlink/streamlink

Issue:
plugins.pandalive: 500 Server Error: Internal Server Error
### 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)

### Collaboration

- [x] [I will provide feedback should a pull request be opened with a fix for the plugin](https://github.com/streamlink/streamlink/blob/master/CONTRIBUTING.md#pull-request-feedback)

### Streamlink version

streamlink 7.1.2

### Description

It was fine until yesterday.
It doesn't work from today.
I guess the API changed.
Thank you. Good luck always.

### Debug log

```text
[18:59:55.635406][session][debug] Loading plugin: pandalive
[18:59:55.657412][cli][debug] OS:         Windows 11
[18:59:55.658454][cli][debug] Python:     3.12.8
[18:59:55.658454][cli][debug] OpenSSL:    OpenSSL 3.0.15 3 Sep 2024
[18:59:55.658454][cli][debug] Streamlink: 7.1.2
[18:59:55.658454][cli][debug] Dependencies:
[18:59:55.659449][cli][debug]  certifi: 2024.12.14
[18:59:55.663986][cli][debug]  isodate: 0.7.2
[18:59:55.663986][cli][debug]  lxml: 5.3.0
[18:59:55.665027][cli][debug]  pycountry: 24.6.1
[18:59:55.665027][cli][debug]  pycryptodome: 3.21.0
[18:59:55.665027][cli][debug]  PySocks: 1.7.1
[18:59:55.665027][cli][debug]  requests: 2.32.3
[18:59:55.666033][cli][debug]  trio: 0.28.0
[18:59:55.666033][cli][debug]  trio-websocket: 0.11.1
[18:59:55.667020][cli][debug]  urllib3: 2.3.0
[18:59:55.667020][cli][debug]  websocket-client: 1.8.0
[18:59:55.667020][cli][debug] Arguments:
[18:59:55.667020][cli][debug]  url=https://www.pandalive.co.kr/live/play/#
[18:59:55.667020][cli][debug]  stream=['best']
[18:59:55.667020][cli][debug]  --loglevel=trace
[18:59:55.667020][cli][debug]  --logfile=C:/Users/#/Documents/#/bat/{date_value}/{ndh}.log
[18:59:55.667020][cli][debug]  --output=C:/Users/#/Documents/#/bat/{date_value}/{ndh}.ts
[18:59:55.667020][cli][debug]  --hls-segment-queue-threshold=5.0
[18:59:55.667020][cli][debug]  --hls-live-restart=True
[18:59:55.667020][cli][debug]  --ffmpeg-ffmpeg=C:\Program Files\Streamlink\ffmpeg\ffmpeg.exe
[18:59:55.667020][cli][debug]  --http-cookie=[('sessKey', '#')]
[18:59:55.668012][cli][info] Found matching plugin pandalive for URL https://www.pandalive.co.kr/live/play/#
error: Unable to open URL: https://www.pandalive.co.kr/live/play/#(500 Server Error: Internal Server Error for url: https://w2.pandalive.co.kr/play/#)
```


Discussion:
I have the same problem, waiting for fix, thanks



Patch:
diff --git a/src/streamlink/plugins/pandalive.py b/src/streamlink/plugins/pandalive.py
index eed3e743383..cca90f236f5 100644
--- a/src/streamlink/plugins/pandalive.py
+++ b/src/streamlink/plugins/pandalive.py
@@ -18,22 +18,45 @@
 
 
 @pluginmatcher(
-    re.compile(r"https?://(?:www\.)?pandalive\.co\.kr/live/play/[^/]+"),
+    re.compile(r"https?://(?:\w+\.)?pandalive\.co\.kr/(?:\w+/)?play/(?P<channel>[^/#?]+)"),
 )
 class Pandalive(Plugin):
+    _URL_API_MEMBER = "https://api.pandalive.co.kr/v1/member/bj"
+
     def _get_streams(self):
-        media_code = self.session.http.get(
-            self.url,
+        result, user_id = self.session.http.post(
+            self._URL_API_MEMBER,
+            data={"userId": self.match["channel"]},
+            raise_for_status=False,
             schema=validate.Schema(
-                re.compile(r"""routePath:\s*(?P<q>["'])(\\u002F|/)live(\\u002F|/)play(\\u002F|/)(?P<id>.+?)(?P=q)"""),
-                validate.any(None, validate.get("id")),
+                validate.parse_json(),
+                validate.any(
+                    validate.all(
+                        {
+                            "result": False,
+                            "message": str,
+                        },
+                        validate.union_get("result", "message"),
+                    ),
+                    validate.all(
+                        {
+                            "bjInfo": {
+                                "idx": int,
+                            },
+                        },
+                        validate.get(("bjInfo", "idx")),
+                        validate.transform(lambda data: (True, data)),
+                    ),
+                ),
             ),
         )
-
-        if not media_code:
+        if not result:
+            log.error(user_id or "Failed to get user ID")
+            return
+        if not user_id:
             return
 
-        log.debug(f"Media code: {media_code}")
+        log.debug(f"{user_id=}")
 
         json = self.session.http.post(
             "https://api.pandalive.co.kr/v1/live/play",
@@ -42,7 +65,7 @@ def _get_streams(self):
             },
             data={
                 "action": "watch",
-                "userId": media_code,
+                "userId": user_id,
             },
             acceptable_status=(200, 400),
             schema=validate.Schema(


Test patch:
diff --git a/tests/plugins/test_pandalive.py b/tests/plugins/test_pandalive.py
index 750bbd1d172..e56d8512221 100644
--- a/tests/plugins/test_pandalive.py
+++ b/tests/plugins/test_pandalive.py
@@ -5,6 +5,7 @@
 class TestPluginCanHandleUrlPandalive(PluginCanHandleUrl):
     __plugin__ = Pandalive
 
-    should_match = [
-        "https://www.pandalive.co.kr/live/play/CHANNEL",
+    should_match_groups = [
+        ("https://www.pandalive.co.kr/live/play/CHANNEL", {"channel": "CHANNEL"}),
+        ("https://w2.pandalive.co.kr/en/play/CHANNEL", {"channel": "CHANNEL"}),
     ]