Repository: streamlink/streamlink

Issue:
Recurring issue with live streams
Hi,

I successfully make working some live streams but i experienced an issue and i can't show everything and even if i post a link of a master .m3u8, it will not work because it needs an authentication as well. (cookies with sensitive stuff)

I try this way : 

livestreamer --http-header "User-Agent=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36" --http-cookie "cookie=###########" --player-continuous-http --  "hlsvariant://https://ncdn.***.sfr.fr/iphone/tf1_no_vmst_hd.m3u8?msisdn=*-9****V&transid=er_error&ServiceId=pctv&gt=1*******0&loginterval=0&media=pctv&life=3600&tokenname=SFRPLAY3&key=**********" best

Everything work but after one minute, sometimes a bit more the stream stops and i got this on the shell : 

```
[cli][info] Available streams: 180p (worst), 360p, 576p, 720p (best)
[cli][info] Starting player: /usr/bin/vlc
[cli][info] Got HTTP request from VLC/2.2.4 LibVLC/2.2.4
[cli][info] Opening stream: 720p (hls)


Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 810, in __bootstrap_inner
    self.run()
  File "/usr/lib/python2.7/dist-packages/livestreamer/stream/segmented.py", line 160, in run
    self.write(segment, result)
  File "/usr/lib/python2.7/dist-packages/livestreamer/stream/hls.py", line 89, in write
    sequence.num)
  File "/usr/lib/python2.7/dist-packages/livestreamer/stream/hls.py", line 46, in create_decryptor
    **self.reader.request_params)
  File "/usr/lib/python2.7/dist-packages/requests/sessions.py", line 469, in get
    return self.request('GET', url, **kwargs)
  File "/usr/lib/python2.7/dist-packages/livestreamer/plugin/api/http_session.py", line 128, in request
    *args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/requests/sessions.py", line 457, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/lib/python2.7/dist-packages/requests/sessions.py", line 569, in send
    r = adapter.send(request, **kwargs)
  File "/usr/lib/python2.7/dist-packages/requests/adapters.py", line 362, in send
    timeout=timeout
  File "/usr/lib/python2.7/dist-packages/urllib3/connectionpool.py", line 516, in urlopen
    body=body, headers=headers)
  File "/usr/lib/python2.7/dist-packages/urllib3/connectionpool.py", line 331, in _make_request
    httplib_response = conn.getresponse(buffering=True)
  File "/usr/lib/python2.7/httplib.py", line 1111, in getresponse
    response.begin()
  File "/usr/lib/python2.7/httplib.py", line 444, in begin
    version, status, reason = self._read_status()
  File "/usr/lib/python2.7/httplib.py", line 400, in _read_status
    line = self.fp.readline(_MAXLINE + 1)
  File "/usr/lib/python2.7/socket.py", line 476, in readline
    data = self._sock.recv(self._rbufsize)
  File "/usr/lib/python2.7/dist-packages/urllib3/contrib/pyopenssl.py", line 200, in recv
    return self.recv(*args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/urllib3/contrib/pyopenssl.py", line 188, in recv
    data = self.connection.recv(*args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/OpenSSL/SSL.py", line 995, in recv
    self._raise_ssl_error(self._ssl, result)
  File "/usr/lib/python2.7/dist-packages/OpenSSL/SSL.py", line 862, in _raise_ssl_error
    raise SysCallError(errno, errorcode[errno])
SysCallError: (104, 'ECONNRESET')

[cli][error] Error when reading from stream: Read timeout
[cli][info] Stream ended
[cli][info] Got HTTP request from VLC/2.2.4 LibVLC/2.2.4
[cli][info] Opening stream: 720p (hls)
```

It does that indefinitely. it is a loop ! I have to wait 20-30 seconds before the live stream restarts.

I hope there is an easy workaround to fix this issue.

I tried this from Debian 8

Thanks.


Discussion:
Here is an example of a master m3u8

```
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=363878,RESOLUTION=320x180,CODECS="mp4a.40.5,avc1.42c01e"
http://ncdn-sr.adam.sfr.fr/iphone/bfm_sport_299968/bfm_sport.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=663910,RESOLUTION=640x360,CODECS="mp4a.40.5,avc1.42c01e"
http://ncdn-sr.adam.sfr.fr/iphone/bfm_sport_600000/bfm_sport.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1063910,RESOLUTION=640x360,CODECS="mp4a.40.5,avc1.42c01e"
http://ncdn-sr.adam.sfr.fr/iphone/bfm_sport_1000000/bfm_sport.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2063910,RESOLUTION=1024x576,CODECS="mp4a.40.5,avc1.4d401f"
http://ncdn-sr.adam.sfr.fr/iphone/bfm_sport_2000000/bfm_sport.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=3063910,RESOLUTION=1280x720,CODECS="mp4a.40.5,avc1.640028"
http://ncdn-sr.adam.sfr.fr/iphone/bfm_sport_3000000/bfm_sport.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=4063910,RESOLUTION=1280x720,CODECS="mp4a.40.5,avc1.640028"
http://ncdn-sr.adam.sfr.fr/iphone/bfm_sport_4000000/bfm_sport.m3u8
```


And this...
```
#EXTM3U
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:26877
#EXT-X-VERSION:4
#EXT-X-KEY:METHOD=AES-128,URI="https://ncdn.adam.sfr.fr/iphone/bfm_sport_4000000/key4479"
#EXTINF:9.96,
http://abv1-ncdn-edge-video00.cdn.sfr.fr/ncdn-sr.adam.sfr.fr/iphone/bfm_sport_4000000/bfm_sport00026877.ts
#EXTINF:9.96,
http://abv1-ncdn-edge-video00.cdn.sfr.fr/ncdn-sr.adam.sfr.fr/iphone/bfm_sport_4000000/bfm_sport00026878.ts
#EXTINF:9.96,
http://abv1-ncdn-edge-video00.cdn.sfr.fr/ncdn-sr.adam.sfr.fr/iphone/bfm_sport_4000000/bfm_sport00026879.ts
#EXT-X-KEY:METHOD=AES-128,URI="https://ncdn.adam.sfr.fr/iphone/bfm_sport_4000000/key4480"
#EXTINF:9.96,
http://abv1-ncdn-edge-video00.cdn.sfr.fr/ncdn-sr.adam.sfr.fr/iphone/bfm_sport_4000000/bfm_sport00026880.ts
#EXTINF:9.96,
http://abv1-ncdn-edge-video00.cdn.sfr.fr/ncdn-sr.adam.sfr.fr/iphone/bfm_sport_4000000/bfm_sport00026881.ts
```

I noticed on the browser console that a key is requested every minute.

Thanks for any suggestion.

Resolving patch:
diff --git a/src/streamlink/stream/hls.py b/src/streamlink/stream/hls.py
--- a/src/streamlink/stream/hls.py
+++ b/src/streamlink/stream/hls.py
@@ -39,6 +39,7 @@ def create_decryptor(self, key, sequence):
 
         if self.key_uri != key.uri:
             res = self.session.http.get(key.uri, exception=StreamError,
+                                        retries=self.retries,
                                         **self.reader.request_params)
             self.key_data = res.content
             self.key_uri = key.uri


Test patch: