Repository: streamlink/streamlink

Issue:
plugins.tf1: "stream" matcher URL format has changed
### Checklist

- [x] This is a bug report 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 bug reports](https://github.com/streamlink/streamlink/issues?q=is%3Aissue+label%3A%22bug%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 problem](https://github.com/streamlink/streamlink/blob/master/CONTRIBUTING.md#pull-request-feedback)

### Streamlink version

Your Streamlink version (7.1.3)

### Description

Hello, I would like to stream the FAST channels of TF1+, but I get this error: error: Unable to open URL: https://mediainfo.tf1.fr/mediainfocombo/L_THRILLER-FICTION-89242722 (404 Client Error: Not Found for url: https://mediainfo.tf1.fr/mediainfocombo/L_THRILLER-FICTION-89242722?context=MYTF1&pver=5015000)

While there are no issues with the 'normal' TF1 channels."

### Debug log

```text
streamlink --tf1-email="" --tf1-password="" https://www.tf1.fr/thriller-fiction-89242722/direct 

[session][debug] Loading plugin: tf1
[cli][info] streamlink is running as root! Be careful!
[cli][debug] OS:         Linux-5.4.0-205-generic-x86_64-with
[cli][debug] Python:     3.9.13
[cli][debug] OpenSSL:    OpenSSL 1.1.1o  3 May 2022
[cli][debug] Streamlink: 7.1.3
[cli][debug] Dependencies:
[cli][debug]  certifi: 2025.1.31
[cli][debug]  exceptiongroup: 1.2.2
[cli][debug]  isodate: 0.7.2
[cli][debug]  lxml: 5.3.1
[cli][debug]  pycountry: 24.6.1
[cli][debug]  pycryptodome: 3.21.0
[cli][debug]  PySocks: 1.7.1
[cli][debug]  requests: 2.32.3
[cli][debug]  trio: 0.29.0
[cli][debug]  trio-websocket: 0.11.1
[cli][debug]  urllib3: 2.3.0
[cli][debug]  websocket-client: 1.8.0
[cli][debug] Arguments:
[cli][debug]  url=https://www.tf1.fr/thriller-fiction-89242722/direct
[cli][debug]  --loglevel=debug
[cli][debug]  --tf1-email=remy.wilmet@gmail.com
[cli][debug]  --tf1-password=********
[cli][info] Found matching plugin tf1 for URL https://www.tf1.fr/thriller-fiction-89242722/direct
[plugins.tf1][debug] Found channel thriller-fiction-89242722 (L_THRILLER-FICTION-89242722)
[plugins.tf1][info] Acquiring new user-authentication token...
[plugins.tf1][debug] uid='95939af426164753b62f24338e006aa4' uid_signature='T43/ldsKl96Aqj2G12Z8OUJWIJA=' signature_timestamp='1739912886'
error: Unable to open URL: https://mediainfo.tf1.fr/mediainfocombo/L_THRILLER-FICTION-89242722 (404 Client Error: Not Found for url: https://mediainfo.tf1.fr/mediainfocombo/L_THRILLER-FICTION-89242722?context=MYTF1&pver=5015000)
```

Discussion:

Fix (patch):
diff --git a/src/streamlink/plugins/tf1.py b/src/streamlink/plugins/tf1.py
index 723b6f1f..0568e28b 100644
--- a/src/streamlink/plugins/tf1.py
+++ b/src/streamlink/plugins/tf1.py
@@ -21,11 +21,11 @@ log = logging.getLogger(__name__)
 
 @pluginmatcher(
     name="live",
-    pattern=re.compile(r"https?://(?:www\.)?tf1\.fr/(?P<live>[\w-]+)/direct/?"),
+    pattern=re.compile(r"https?://(?:www\.)?tf1\.fr/(?P<live>(?![\w-]+-\d+)[^/?#]+)/direct/?"),
 )
 @pluginmatcher(
     name="stream",
-    pattern=re.compile(r"https?://(?:www\.)?tf1\.fr/stream/(?P<stream>[\w-]+)"),
+    pattern=re.compile(r"https?://(?:www\.)?tf1\.fr/(?P<stream>[\w-]+-\d+)/direct/?"),
 )
 @pluginmatcher(
     name="lci",


Test changes:
diff --git a/tests/plugins/test_tf1.py b/tests/plugins/test_tf1.py
index 9c4fa3b5..939cfa48 100644
--- a/tests/plugins/test_tf1.py
+++ b/tests/plugins/test_tf1.py
@@ -10,8 +10,8 @@ class TestPluginCanHandleUrlTF1(PluginCanHandleUrl):
         (("live", "https://www.tf1.fr/tf1/direct"), {"live": "tf1"}),
         (("live", "https://www.tf1.fr/tfx/direct"), {"live": "tfx"}),
         (("live", "https://www.tf1.fr/tf1-series-films/direct"), {"live": "tf1-series-films"}),
-        (("stream", "https://www.tf1.fr/stream/chante-69061019"), {"stream": "chante-69061019"}),
-        (("stream", "https://www.tf1.fr/stream/arsene-lupin-39652174"), {"stream": "arsene-lupin-39652174"}),
+        (("stream", "https://www.tf1.fr/chante-69061019/direct"), {"stream": "chante-69061019"}),
+        (("stream", "https://www.tf1.fr/thriller-fiction-89242722/direct"), {"stream": "thriller-fiction-89242722"}),
         (("lci", "https://lci.fr/direct"), {}),
         (("lci", "https://www.lci.fr/direct"), {}),
         (("lci", "https://tf1info.fr/direct/"), {}),