Repository: streamlink/streamlink

Issue:
plugins.ustvnow: pluginmatcher URL update needed
### Checklist

- [X] This is a plugin issue and not a different kind of issue
- [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

Latest build from the master branch

### Description

You need to replace the search template in ustvnow.py plugin with the one below.

```
@pluginmatcher(re.compile(                                                                                                                                     
    r"https?://(?:www\.)?ustvnow\.com/channel/live/(?P<chname>\w+)",                                                                                           
))
```
What is in the code now - does not work due to changes that have occurred on the site www.ustvnow.com

### Debug log

```text
The log cannot be retrieved because changes must be made to the template of the link it "serves"
```


Discussion:
gravyboat: > If there's no feedback, then I'm going to remove the plugin instead, because I can't maintain it myself, and nobody else with access has shown any interest whatsoever in maintaining it.

Sounds like the better plan to me!
MajinLugia: C:\Users\User>streamlink --loglevel debug https://www.ustvnow.com/channel/live/pbs_kids best --ustvnow-username censored@censored.com --ustvnow-password censored
[cli][debug] OS:         Windows 11
[cli][debug] Python:     3.12.2
[cli][debug] OpenSSL:    OpenSSL 3.0.13 30 Jan 2024
[cli][debug] Streamlink: 6.6.2
[cli][debug] Dependencies:
[cli][debug]  certifi: 2024.2.2
[cli][debug]  isodate: 0.6.1
[cli][debug]  lxml: 5.1.0
[cli][debug]  pycountry: 23.12.11
[cli][debug]  pycryptodome: 3.20.0
[cli][debug]  PySocks: 1.7.1
[cli][debug]  requests: 2.31.0
[cli][debug]  trio: 0.24.0
[cli][debug]  trio-websocket: 0.11.1
[cli][debug]  typing-extensions: 4.9.0
[cli][debug]  urllib3: 2.2.0
[cli][debug]  websocket-client: 1.7.0
[cli][debug] Arguments:
[cli][debug]  url=https://www.ustvnow.com/channel/live/pbs_kids
[cli][debug]  stream=['best']
[cli][debug]  --loglevel=debug
[cli][debug]  --ffmpeg-ffmpeg=C:\Program Files\Streamlink\ffmpeg\ffmpeg.exe
[cli][debug]  --ustvnow-username=censored@censored.com
[cli][debug]  --ustvnow-password=********
error: No plugin can handle URL: https://www.ustvnow.com/channel/live/pbs_kids

........not sure if I did this correctly....... 

Patch:
diff --git a/src/streamlink/plugins/ustvnow.py b/src/streamlink/plugins/ustvnow.py
index b14e8005..0b4ea184 100644
--- a/src/streamlink/plugins/ustvnow.py
+++ b/src/streamlink/plugins/ustvnow.py
@@ -21,7 +21,7 @@ log = logging.getLogger(__name__)
 
 
 @pluginmatcher(re.compile(
-    r"https?://(?:www\.)?ustvnow\.com/live/(?P<scode>\w+)/-(?P<id>\d+)",
+    r"https?://(?:www\.)?ustvnow\.com/channel/live/(?P<chname>\w+)",
 ))
 @pluginargument(
     "username",
@@ -96,11 +96,6 @@ class USTVNow(Plugin):
         return self.cache.get("box_id")
 
     def get_token(self):
-        """
-        Get the token for USTVNow
-        :return: a valid token
-        """
-
         if not self._token:
             log.debug("Getting new session token")
             res = self.session.http.get(self._token_url, params={
@@ -114,13 +109,13 @@ class USTVNow(Plugin):
             })
 
             data = res.json()
-            if data["status"]:
-                self._token = data["response"]["sessionId"]
-                log.debug("New token: {}".format(self._token))
-            else:
+            if not data["status"]:
                 log.error("Token acquisition failed: {details} ({detail})".format(**data["error"]))
                 raise PluginError("could not obtain token")
 
+            self._token = data["response"]["sessionId"]
+            log.debug(f"New token: {self._token}")
+
         return self._token
 
     def api_request(self, path, data, metadata=None):
@@ -153,21 +148,20 @@ class USTVNow(Plugin):
         return resp["data"]["status"]
 
     def _get_streams(self):
-        """
-        Finds the streams from ustvnow.com.
-        """
-        if self.login(self.get_option("username"), self.get_option("password")):
-            path = urlparse(self.url).path.strip("/")
-            resp = self.api_request("send", {"path": path}, {"request": "page/stream"})
-            if resp["data"]["status"]:
-                for stream in resp["data"]["response"]["streams"]:
-                    if stream["keys"]["licenseKey"]:
-                        log.warning("Stream possibly protected by DRM")
-                    yield from HLSStream.parse_variant_playlist(self.session, stream["url"]).items()
-            else:
-                log.error("Could not find any streams: {code}: {message}".format(**resp["data"]["error"]))
-        else:
+        if not self.login(self.get_option("username"), self.get_option("password")):
             log.error("Failed to login, check username and password")
+            return
+
+        path = urlparse(self.url).path.strip("/")
+        resp = self.api_request("send", {"path": path}, {"request": "page/stream"})
+        if not resp["data"]["status"]:
+            log.error("Could not find any streams: {code}: {message}".format(**resp["data"]["error"]))
+            return
+
+        for stream in resp["data"]["response"]["streams"]:
+            if stream["keys"]["licenseKey"]:
+                log.warning("Stream possibly protected by DRM")
+            yield from HLSStream.parse_variant_playlist(self.session, stream["url"]).items()
 
 
 __plugin__ = USTVNow


Test patch:
diff --git a/tests/plugins/test_ustvnow.py b/tests/plugins/test_ustvnow.py
index 7a3d8a98..626a2dc7 100644
--- a/tests/plugins/test_ustvnow.py
+++ b/tests/plugins/test_ustvnow.py
@@ -6,7 +6,7 @@ class TestPluginCanHandleUrlUSTVNow(PluginCanHandleUrl):
     __plugin__ = USTVNow
 
     should_match = [
-        "http://www.ustvnow.com/live/foo/-65",
+        "https://www.ustvnow.com/channel/live/cbs",
     ]