Repository: streamlink/streamlink

Issue:
tf1 plugin better stream
Hi,

Are you sure there isn't better stream than 360p for TF1 ?
[cli][info] Found matching plugin tf1 for URL https://www.tf1.fr/tf1/direct
[cli][info] Available streams: 496k (worst), 234p_alt, 234p, 896k, 360p_alt, 360p (best)

I have a far better quality with a web browser than best.


Discussion:
It's always difficult answering issues when people don't fill out the template. Please do this next time, so it is clear to us and everyone else which Streamlink version you are using.

> Available streams: 496k (worst), 234p_alt, 234p, 896k, 360p_alt, 360p (best)

In order to select the "best" stream, all of the available streams first need to be sorted by their "weight". Since there are different kind of formats being returned from the master playlist (resolution based with an unknown bitrate and bitrate based with an unknown resolution), Streamlink somehow needs to convert them into a common format. That's being done here:
https://github.com/streamlink/streamlink/blob/0.11.0/src/streamlink/plugin/plugin.py#L51-L88

As you can see, the streams which are described by their bitrate ("k" suffix) get their weight from the bitrate divided by `BIT_RATE_WEIGHT_RATIO`, which is equal to `2.8`, and streams which are described by their resolution ("p" suffix) get their weight from the video height (plus frame rate, if available). The number `2.8` was defined by Chrippa 5 years ago and hasn't been changed since, see ddad859c9d6c5c791722536f8051222ba255d3fa. This formula is basically just an assumption of how big the resolution of a stream might be according to its bitrate, but it's not an ideal solution.

The stream_weight method need to get overridden in the plugin to fix this issue, or someone could make the `BIT_RATE_WEIGHT_RATIO` more dynamic, but for now, you can solve your issue by simply selecting the intended stream (896k) instead of "best"...
It looks like 896k is also 360p, so probably they are the same - one is HDS and the other is HLS. It's possible that there are other stream types available, that aren't supported by streamlink that are higher quality. Maybe @BZHDeveloper will have some more information. 
no better qualities for TF1 live, sorry :)

see m3u8 info

>#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=496000,RESOLUTION=416x234,CODECS="avc1.66.30, mp4a.40.2"

>#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=496000,RESOLUTION=416x234,CODECS="avc1.66.30, mp4a.40.2"

>#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=896000,RESOLUTION=640x360,CODECS="avc1.66.30, mp4a.40.2"

>#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=896000,RESOLUTION=640x360,CODECS="avc1.66.30, mp4a.40.2"
Closing thanks to the comment by @BZHDeveloper.
NOTE (after investigation)  : TF1 group now use MPD format for his livestreams
it's possible

```
[cli][info] Found matching plugin tf1 for URL https://www.tf1.fr/tf1/direct
[cli][info] Available streams: 496k (worst), 234p_alt, 234p, 896k, 360p_alt, 360p,
1328k, 576p_alt, 576p, 720p_alt, 720p, 2328k (best)
```

you need to change the url parameters

OLD URL:

http://.../...?hdnea=...&n=...&\_\_b\_\_=...&b=...

NEW URL:

http://.../...?hdnea=...

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,6 +1,7 @@
 from __future__ import print_function
 import re
 
+from streamlink.compat import urlparse, parse_qsl
 from streamlink.plugin import Plugin
 from streamlink.plugin.api import http, useragents
 from streamlink.stream import HDSStream
@@ -41,8 +42,9 @@ def _get_hls_streams(self, channel):
 
         m = self.embed_re.search(embed_page.text)
         if m:
-            hls_stream_url = m.group(1)
-
+            o = urlparse(m.group(1))
+            prms = dict(parse_qsl(o.query))
+            hls_stream_url = "{0}://{1}{2}?hdnea={3}".format(o.scheme, o.netloc, o.path, prms["hdnea"])
             try:
                 for s in HLSStream.parse_variant_playlist(self.session, hls_stream_url).items():
                     yield s


Test patch: