Repository: streamlink/streamlink

Issue:
Twitch --retry-streams stop working after internet connection loss and recovery
<!--
Thanks for reporting a bug!
USE THE TEMPLATE. Otherwise your bug report may be rejected.

First, see the contribution guidelines:
https://github.com/streamlink/streamlink/blob/master/CONTRIBUTING.md#contributing-to-streamlink

Also check the list of open and closed bug reports:
https://github.com/streamlink/streamlink/issues?q=is%3Aissue+label%3A%22bug%22

Please see the text preview to avoid unnecessary formatting errors.
-->


## Bug Report

<!-- Replace [ ] with [x] in order to check the box -->
- [x] This is a bug report and I have read the contribution guidelines.


### Description

<!-- Explain the bug as thoroughly as you can. Don't leave out information which is necessary for us to reproduce and debug this issue. -->
Using the command: ` streamlink -o file --twitch-disable-hosting --retry-streams 5 --loglevel debug twitch.tv/example best` while the streamer is offline, then losing internet connection and reestablishing it, leaves streamlink unable to record the stream when the streamer comes online later on, even though log messages say it's attempting to get live HLS streams.
Forcing close and running command again is necessary.

### Expected / Actual behavior

<!-- What do you expect to happen, and what is actually happening? -->
Expected streamlinks to recognize that the stream went online and start recording, OR close the process despite the "--retry-streams" flag due client internet loss.

### Reproduction steps / Explicit stream URLs to test

<!-- How can we reproduce this? Please note the exact steps below using the list format supplied. If you need more steps please add them. -->

1. Make sure the twitch streamer to be tested is offline
2. Run ` streamlink -o file --twitch-disable-hosting --retry-streams 5 --loglevel debug twitch.tv/mizkif best`
3. Cut internet connection
4. Wait until timeout error
5. Reestablish internet connection
6. When streamer comes online, streamlink is unable to detect the stream despite log messages attempting to get HLS stream

### Log output

<!--
TEXT LOG OUTPUT IS REQUIRED for a bug report!
Use the `--loglevel debug` parameter and avoid using parameters which suppress log output.
https://streamlink.github.io/cli.html#cmdoption-l

Make sure to **remove usernames and passwords**
You can copy the output to https://gist.github.com/ or paste it below.
-->

```
PS C:\1> streamlink -o file --twitch-disable-hosting --retry-streams 5 --loglevel debug twitch.tv/mizkif best
[cli][debug] OS:         Windows 7
[cli][debug] Python:     3.6.6
[cli][debug] Streamlink: 1.3.0
[cli][debug] Requests(2.22.0), Socks(1.7.1), Websocket(0.56.0)
[cli][info] Found matching plugin twitch for URL twitch.tv/mizkif
[cli][debug] Plugin specific arguments:
[cli][debug]  --twitch-disable-hosting=True (disable_hosting)
[plugin.twitch][debug] Getting live HLS streams for mizkif
[plugin.twitch][info] mizkif is hosting erobb221
[plugin.twitch][info] hosting was disabled by command line option
[utils.l10n][debug] Language code: pt_BR
[cli][info] Waiting for streams, retrying every 5.0 second(s)
[plugin.twitch][debug] Getting live HLS streams for mizkif
[cli][error] Unable to open URL: https://tmi.twitch.tv/hosts (HTTPSConnectionPool(host='tmi.twitch.tv', port=443): Read
timed out. (read timeout=20.0))
[plugin.twitch][debug] Getting live HLS streams for mizkif
[cli][error] Unable to open URL: https://tmi.twitch.tv/hosts (HTTPSConnectionPool(host='tmi.twitch.tv', port=443): Max r
etries exceeded with url: /hosts?as3=t&include_logins=1&host=94753024 (Caused by NewConnectionError('<urllib3.connection
.VerifiedHTTPSConnection object at 0x045904F0>: Failed to establish a new connection: [Errno 11004] getaddrinfo failed',
)))
[plugin.twitch][debug] Getting live HLS streams for mizkif
[cli][error] Unable to open URL: https://tmi.twitch.tv/hosts (HTTPSConnectionPool(host='tmi.twitch.tv', port=443): Max r
etries exceeded with url: /hosts?as3=t&include_logins=1&host=94753024 (Caused by NewConnectionError('<urllib3.connection
.VerifiedHTTPSConnection object at 0x04590290>: Failed to establish a new connection: [Errno 11004] getaddrinfo failed',
)))
[plugin.twitch][debug] Getting live HLS streams for mizkif
[plugin.twitch][info] mizkif is hosting erobb221
[plugin.twitch][info] hosting was disabled by command line option
[plugin.twitch][debug] Getting live HLS streams for mizkif
[plugin.twitch][info] mizkif is hosting erobb221
```


### Additional comments, screenshots, etc.
Changing/using a VPN also causes the same issue.
Issue doesn't seem to be channel dependent.

[Love Streamlink? Please consider supporting our collective. Thanks!](https://opencollective.com/streamlink/donate)



Discussion:
Still same problem on 1.4.1.
```
PS D:\twitch> streamlink -o stream.mp4 --retry-streams 10 --loglevel debug twitch.tv/test115 best
[cli][debug] OS:         Windows 10
[cli][debug] Python:     3.6.6
[cli][debug] Streamlink: 1.4.1
[cli][debug] Requests(2.23.0), Socks(1.7.1), Websocket(0.57.0)
[cli][info] Found matching plugin twitch for URL twitch.tv/test115
[plugin.twitch][debug] Getting live HLS streams for test115
[utils.l10n][debug] Language code: en_US
[cli][info] Waiting for streams, retrying every 10.0 second(s)
[plugin.twitch][debug] Getting live HLS streams for test115
[utils.l10n][debug] Language code: en_US
[plugin.twitch][debug] Getting live HLS streams for test115
[utils.l10n][debug] Language code: en_US
[plugin.twitch][debug] Getting live HLS streams for test115
[utils.l10n][debug] Language code: en_US
[plugin.twitch][debug] Getting live HLS streams for test115
[cli][error] Unable to open URL: https://tmi.twitch.tv/hosts (('Connection aborted.', ConnectionResetError(10054, 'An existing connection was forcibly closed by the remote host', None, 10054, None)))
[plugin.twitch][debug] Getting live HLS streams for test115
[cli][error] Unable to open URL: https://tmi.twitch.tv/hosts (HTTPSConnectionPool(host='tmi.twitch.tv', port=443): Max retries exceeded with url: /hosts?as3=t&include_logins=1&host=94753024 (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x0509CCB0>: Failed to establish a new connection: [Errno 11001] getaddrinfo failed',)))
[plugin.twitch][debug] Getting live HLS streams for test115
[cli][error] Unable to open URL: https://tmi.twitch.tv/hosts (HTTPSConnectionPool(host='tmi.twitch.tv', port=443): Max retries exceeded with url: /hosts?as3=t&include_logins=1&host=94753024 (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x0509C7B0>: Failed to establish a new connection: [Errno 11001] getaddrinfo failed',)))
[plugin.twitch][debug] Getting live HLS streams for test115
[plugin.twitch][debug] Getting live HLS streams for test115
[plugin.twitch][debug] Getting live HLS streams for test115
[plugin.twitch][debug] Getting live HLS streams for test115
```
As TS said, even if the user goes online, a "Getting live HLS streams" will always be shown in streamlink.
Only one difference that I see after reestablishing the connection there is no "[utils.l10n][debug] Language code: en_US" line anymore.
After "Unable to open URL: https://usher.ttvnw.net" streamlink is still able to check, but after some twitch problems streamlink stops working properly. 

```
streamlink -o stream.mp4 --retry-streams 1 --loglevel debug twitch.tv/test115 best
[cli][debug] OS:         Windows 10
[cli][debug] Python:     3.6.6
[cli][debug] Streamlink: 1.4.1
[cli][debug] Requests(2.23.0), Socks(1.7.1), Websocket(0.57.0)
[cli][info] Found matching plugin twitch for URL twitch.tv/test115
[plugin.twitch][debug] Getting live HLS streams for test115
[utils.l10n][debug] Language code: en_US
[cli][info] Waiting for streams, retrying every 1.0 second(s)
[plugin.twitch][debug] Getting live HLS streams for test115
[utils.l10n][debug] Language code: en_US
[plugin.twitch][debug] Getting live HLS streams for test115
[utils.l10n][debug] Language code: en_US
[plugin.twitch][debug] Getting live HLS streams for test115
[utils.l10n][debug] Language code: en_US
[plugin.twitch][debug] Getting live HLS streams for test115
[utils.l10n][debug] Language code: en_US

..... many many same lines

[plugin.twitch][debug] Getting live HLS streams for test115
[cli][error] Unable to open URL: https://usher.ttvnw.net/api/channel/hls/test115.m3u8?player=twitchweb&p=483392&type=any&allow_source=true&allow_audio_only=true&allow_spectre=false&sig=bf787c6a0f739501dacfb68c6384e34b0b37b732&token=%7B%22adblock%22%3Afalse%2C%22authorization%22%3A%7B%22forbidden%22%3Afalse%2C%22reason%22%3A%22%22%7D%2C%22blackout_enabled%22%3Afalse%2C%22channel%22%3A%22test115%22%2C%22channel_id%22%3A195166073%2C%22chansub%22%3A%7B%22restricted_bitrates%22%3A%5B%5D%2C%22view_until%22%3A1924905600%7D%2C%22ci_gb%22%3Afalse%2C%22geoblock_reason%22%3A%22%22%2C%22device_id%22%3Anull%2C%22expires%22%3A1588956923%2C%22extended_history_allowed%22%3Afalse%2C%22game%22%3A%22Just+Chatting%22%2C%22hide_ads%22%3Afalse%2C%22https_required%22%3Afalse%2C%22mature%22%3Afalse%2C%22partner%22%3Afalse%2C%22platform%22%3Anull%2C%22player_type%22%3Anull%2C%22private%22%3A%7B%22allowed_to_view%22%3Atrue%7D%2C%22privileged%22%3Afalse%2C%22server_ads%22%3Atrue%2C%22show_ads%22%3Atrue%2C%22subscriber%22%3Afalse%2C%22turbo%22%3Afalse%2C%22user_id%22%3Anull%2C%22user_ip%22%3A%2278.85.41.135%22%2C%22version%22%3A2%7D&fast_bread=True (('Connection aborted.', RemoteDisconnected('Remote end closed connection without response',)))
[plugin.twitch][debug] Getting live HLS streams for test115
[utils.l10n][debug] Language code: en_US
[plugin.twitch][debug] Getting live HLS streams for test115
[utils.l10n][debug] Language code: en_US
[plugin.twitch][debug] Getting live HLS streams for test115
[cli][error] Unable to open URL: https://tmi.twitch.tv/hosts (HTTPSConnectionPool(host='tmi.twitch.tv', port=443): Read timed out. (read timeout=20.0))
[plugin.twitch][debug] Getting live HLS streams for test115
[cli][error] Unable to open URL: https://tmi.twitch.tv/api/channels/test115/access_token.json (HTTPSConnectionPool(host='tmi.twitch.tv', port=443): Read timed out. (read timeout=20.0))
[plugin.twitch][debug] Getting live HLS streams for test115
[plugin.twitch][debug] Getting live HLS streams for test115
[plugin.twitch][debug] Getting live HLS streams for test115
```
It even drops RAM usage after error appears.
![image](https://user-images.githubusercontent.com/51099894/81439903-d17d3180-9177-11ea-8ffc-728df1d7a7b5.png)

I fixed it for myself. I just added ```break``` in ```except PluginError as err:``` in streamlink_cli\main.py
```
    while not streams:
        sleep(interval)

        try:
            streams = fetch_streams(plugin)
        except FatalPluginError:
            raise
        except PluginError as err:
            log.error(u"{0}".format(err))
            break

        if count > 0:
            attempts += 1
            if attempts >= count:
                break

    return streams
```
I do not know if this is the correct solution to the problem. But since my streamlink starts in a loop, this solves my problem.
According to my tests, the streamlink stops working only when an error occurs when accessing https://tmi.twitch.tv/. I will test more, but for now I made this:
```
    while not streams:
        sleep(interval)

        try:
            streams = fetch_streams(plugin)
        except FatalPluginError:
            raise
        except PluginError as err:
            log.error(u"{0}".format(err))
            if str(err).find("https://tmi.twitch.tv/") != -1:
                break

        if count > 0:
            attempts += 1
            if attempts >= count:
                break

    return streams
```
I added ```log.debug("{0}".format(str(err)))``` in streamlink\plugins\twitch.py in ```def _access_token``` and there is what I got:
```
[13:28:18,9][cli][debug] OS:         Windows 10
[13:28:18,9][cli][debug] Python:     3.6.6
[13:28:18,9][cli][debug] Streamlink: 1.4.1 (retry test)
[13:28:18,9][cli][debug] Requests(2.23.0), Socks(1.7.1), Websocket(0.57.0)
[13:28:18,9][cli][info] Found matching plugin twitch for URL twitch.tv/test115
[13:28:18,9][plugin.twitch][debug] Getting live HLS streams for test115
[13:28:20,41][utils.l10n][debug] Language code: en_US
[13:28:20,546][cli][info] Waiting for streams, retrying every 1.0 second(s)
[13:28:21,547][plugin.twitch][debug] Getting live HLS streams for test115
[13:28:22,22][utils.l10n][debug] Language code: en_US

//INTERNET OFF

[13:28:23,235][plugin.twitch][debug] Getting live HLS streams for test115
[13:28:23,712][utils.l10n][debug] Language code: en_US
[13:28:23,801][cli][error] Unable to open URL: https://usher.ttvnw.net/api/channel/hls/test115.m3u8?player=twitchweb&p=101642&type=any&allow_source=true&allow_audio_only=true&allow_spectre=false&sig=17f6467757b6983024228bcf87603476337c60e0&token=%7B%22adblock%22%3Afalse%2C%22authorization%22%3A%7B%22forbidden%22%3Afalse%2C%22reason%22%3A%22%22%7D%2C%22blackout_enabled%22%3Afalse%2C%22channel%22%3A%22test115%22%2C%22channel_id%22%3A69658351%2C%22chansub%22%3A%7B%22restricted_bitrates%22%3A%5B%5D%2C%22view_until%22%3A1924905600%7D%2C%22ci_gb%22%3Afalse%2C%22geoblock_reason%22%3A%22%22%2C%22device_id%22%3Anull%2C%22expires%22%3A1589021290%2C%22extended_history_allowed%22%3Afalse%2C%22game%22%3A%22%22%2C%22hide_ads%22%3Afalse%2C%22https_required%22%3Afalse%2C%22mature%22%3Afalse%2C%22partner%22%3Afalse%2C%22platform%22%3Anull%2C%22player_type%22%3Anull%2C%22private%22%3A%7B%22allowed_to_view%22%3Atrue%7D%2C%22privileged%22%3Afalse%2C%22server_ads%22%3Atrue%2C%22show_ads%22%3Atrue%2C%22subscriber%22%3Afalse%2C%22turbo%22%3Afalse%2C%22user_id%22%3Anull%2C%22user_ip%22%3A%2278.85.41.135%22%2C%22version%22%3A2%7D&fast_bread=True (('Connection aborted.', ConnectionResetError(10054, 'An existing connection was forcibly closed by the remote host', None, 10054, None)))
[13:28:24,802][plugin.twitch][debug] Getting live HLS streams for test115
[13:28:24,808][cli][error] Unable to open URL: https://tmi.twitch.tv/hosts (HTTPSConnectionPool(host='tmi.twitch.tv', port=443): Max retries exceeded with url: /hosts?as3=t&include_logins=1&host=69658351 (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x049094D0>: Failed to establish a new connection: [Errno 11001] getaddrinfo failed',)))
[13:28:25,808][plugin.twitch][debug] Getting live HLS streams for test115
[13:28:25,810][cli][error] Unable to open URL: https://tmi.twitch.tv/hosts (HTTPSConnectionPool(host='tmi.twitch.tv', port=443): Max retries exceeded with url: /hosts?as3=t&include_logins=1&host=69658351 (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x05374B90>: Failed to establish a new connection: [Errno 11001] getaddrinfo failed',)))

//INTERNET ON

[13:28:32,861][plugin.twitch][debug] Getting live HLS streams for test115
[13:28:34,61][plugin.twitch][debug] Unable to open URL: https://tmi.twitch.tv/api/channels/test115/access_token.json (404 Client Error: Not Found for url: https://tmi.twitch.tv/api/channels/test115/access_token.json?as3=t)
[13:28:35,62][plugin.twitch][debug] Getting live HLS streams for test115
[13:28:35,542][plugin.twitch][debug] Unable to open URL: https://tmi.twitch.tv/api/channels/test115/access_token.json (404 Client Error: Not Found for url: https://tmi.twitch.tv/api/channels/test115/access_token.json?as3=t)
```
So, after reconnecting, we get an error:
```
Unable to open URL: https://tmi.twitch.tv/api/channels/test115/access_token.json (404 Client Error: Not Found for url: https://tmi.twitch.tv/api/channels/test115/access_token.json?as3=t)
```

Link must be https://**api**.twitch.tv/api/channels/test115/access_token.json, but link is https://**tmi**.twitch.tv/api/channels/test115/access_token.json.
So, problem in this in twitch.py:
![image](https://user-images.githubusercontent.com/51099894/81472337-21074000-9200-11ea-988e-f12d0d6255ab.png)
If ```response = self.call(path, format=format, schema=schema, **extra_params)``` returns an error - next line ```self.subdomain = subdomain_buffer``` not execute.

Resolving patch:
diff --git a/src/streamlink/plugins/twitch.py b/src/streamlink/plugins/twitch.py
--- a/src/streamlink/plugins/twitch.py
+++ b/src/streamlink/plugins/twitch.py
@@ -306,9 +306,10 @@ def call(self, path, format="json", schema=None, private=False, **extra_params):
     def call_subdomain(self, subdomain, path, format="json", schema=None, **extra_params):
         subdomain_buffer = self.subdomain
         self.subdomain = subdomain
-        response = self.call(path, format=format, schema=schema, **extra_params)
-        self.subdomain = subdomain_buffer
-        return response
+        try:
+            return self.call(path, format=format, schema=schema, **extra_params)
+        finally:
+            self.subdomain = subdomain_buffer
 
     # Public API calls
 


Test patch: