Repository: streamlink/streamlink

Issue:
TF1 group 
## Plugin Issue

- [x] This is a plugin issue and I have read the contribution guidelines.

### Description

Streams from tf1 are not working anymore with streamlink, though it works on their website.

### Reproduction steps / Explicit stream URLs to test

I m using streamlink-0.14.2+84.ga91e134 or older versions on others servers. 

```
/usr/local/bin/streamlink --loglevel debug "https://www.tf1.fr/tf1/direct" best
[cli][info] streamlink is running as root! Be careful!
[cli][debug] OS:         Linux-4.4.0-139-generic-x86_64-with-Ubuntu-16.04-xenial
[cli][debug] Python:     2.7.12
[cli][debug] Streamlink: 0.14.2+84.ga91e134
[cli][debug] Requests(2.18.4), Socks(1.6.7), Websocket(0.44.0)
[cli][info] Found matching plugin tf1 for URL https://www.tf1.fr/tf1/direct
[plugin.tf1][debug] Found channel tf1
[plugin.tf1][debug] Using HDS channel name: androidliveconnect
error: Unable to open URL: http://tf1livhdsstrike-lh.akamaihd.net/z/strike01_1@97257/manifest.f4m?hdnea=st=1548416338~exp=1548418138~acl=/*~hmac=520d4c15de6c568cd6093711ae0757af7d106bd070fcb8633b894e9896bebab6&n=20&b=496,896,1296,1896 (503 Server Error: Service Unavailable for url: http://tf1livhdsstrike-lh.akamaihd.net/z/strike01_1@97257/manifest.f4m?hdnea=st=1548416338~exp=1548418138~acl=/*~hmac=520d4c15de6c568cd6093711ae0757af7d106bd070fcb8633b894e9896bebab6&n=20&b=496,896,1296,1896&g=CJMOWFRATQAD&hdcore=3.1.0)
```


Discussion:
On the website it looks like you need to login, is that a recent change? 
no it's very old the login. 

Resolving patch:
diff --git a/src/streamlink/plugins/tf1.py b/src/streamlink/plugins/tf1.py
--- a/src/streamlink/plugins/tf1.py
+++ b/src/streamlink/plugins/tf1.py
@@ -1,74 +1,43 @@
 from __future__ import print_function
+
+import logging
 import re
 
-from streamlink.compat import urlparse, parse_qsl
+from streamlink.compat import urljoin
 from streamlink.plugin import Plugin
-from streamlink.plugin.api import useragents
-from streamlink.stream import HDSStream
-from streamlink.stream import HLSStream
-from streamlink.utils.url import update_qsd
+from streamlink.stream import DASHStream
+
+log = logging.getLogger(__name__)
 
 
 class TF1(Plugin):
     url_re = re.compile(r"https?://(?:www\.)?(?:tf1\.fr/([\w-]+)/direct|(lci).fr/direct)/?")
-    embed_url = "http://www.wat.tv/embedframe/live{0}"
-    embed_re = re.compile(r"urlLive.*?:.*?\"(http.*?)\"", re.MULTILINE)
-    api_url = "http://www.wat.tv/get/{0}/591997"
-    swf_url = "http://www.wat.tv/images/v70/PlayerLite.swf"
-    hds_channel_remap = {"tf1": "androidliveconnect",
-                         "lci": "androidlivelci",
-                         "tfx": "nt1live",
-                         "hd1": "hd1live",  # renamed to tfx
-                         "tf1-series-films": "hd1live"}
-    hls_channel_remap = {"lci": "LCI",
-                         "tf1": "V4",
-                         "tfx": "nt1",
-                         "tf1-series-films": "hd1"}
+    api_url_base = "https://delivery.tf1.fr/mytf1-wrd/"
+    token = "07e45841-a17a-47cf-af64-a42311bdcc3d"
+
+    def api_call(self, channel):
+        url = urljoin(self.api_url_base, "L_"+channel.upper())
+        req = self.session.http.get(url, params=dict(token=self.token))
+        return self.session.http.json(req)
 
     @classmethod
     def can_handle_url(cls, url):
         return cls.url_re.match(url) is not None
 
-    def _get_hds_streams(self, channel):
-        channel = self.hds_channel_remap.get(channel, "{0}live".format(channel))
-        self.logger.debug("Using HDS channel name: {0}".format(channel))
-        manifest_url = self.session.http.get(self.api_url.format(channel),
-                                params={"getURL": 1},
-                                headers={"User-Agent": useragents.FIREFOX}).text
-
-        for s in HDSStream.parse_manifest(self.session,
-                                          manifest_url,
-                                          pvswf=self.swf_url,
-                                          headers={"User-Agent": useragents.FIREFOX}).items():
-            yield s
-
-    def _get_hls_streams(self, channel):
-        channel = self.hls_channel_remap.get(channel, channel)
-        embed_url = self.embed_url.format(channel)
-        self.logger.debug("Found embed URL: {0}", embed_url)
-        # page needs to have a mobile user agent
-        embed_page = self.session.http.get(embed_url, headers={"User-Agent": useragents.ANDROID})
-
-        m = self.embed_re.search(embed_page.text)
-        if m:
-            # remove all query string arguments except hdnea
-            hls_stream_url = update_qsd(m.group(1), {"hdnea": None}, remove="*")
-            try:
-                for s in HLSStream.parse_variant_playlist(self.session, hls_stream_url).items():
-                    yield s
-            except Exception:
-                self.logger.error("Failed to load the HLS playlist for {0}", channel)
-
     def _get_streams(self):
         m = self.url_re.match(self.url)
         if m:
             channel = m.group(1) or m.group(2)
             self.logger.debug("Found channel {0}", channel)
-            for s in self._get_hds_streams(channel):
-                yield s
-
-            for s in self._get_hls_streams(channel):
-                yield s
+            data = self.api_call(channel)
+
+            if data.get("error"):
+                log.error("Failed to get stream for {0}: {error} ({code})".format(channel, **data))
+            else:
+                log.debug("Got {format} stream {url}".format(**data))
+                if data["format"] == "dash":
+                    for s in DASHStream.parse_manifest(self.session, data["url"]).items():
+                        yield s
 
 
 __plugin__ = TF1


Test patch: