Repository: streamlink/streamlink

Issue:
Goodgame plugin stopped working
### Checklist

- [x] This is a bug report.
- [ ] This is a feature request.
- [x] This is a plugin (improvement) request.
- [x] I have read the contribution guidelines.

### Description

Goodgame plugin is unable to find any playable qualities when specified channel link. Began about 2 days ago, previously was working as usual.

### Expected / Actual behavior

Should locate and print list of available qualities (or start playing in vlc if quality was specified as parameter). 

### Reproduction steps / Explicit stream URLs to test

streamlink -l debug https://goodgame.ru/channel/Foggy

### Logs

[cli][debug] OS:         macOS 10.11.6
[cli][debug] Python:     3.6.1
[cli][debug] Streamlink: 0.12.1
[cli][debug] Requests(2.18.1), Socks(1.6.7), Websocket(0.47.0)
[cli][info] Found matching plugin goodgame for URL https://goodgame.ru/channel/Foggy
error: No playable streams found on this URL: https://goodgame.ru/channel/Foggy



Discussion:
I can confirm.
I do not know if it will be useful, but it works with such a plug-in in the livestreamer:

```python
import re

from livestreamer.plugin import Plugin
from livestreamer.plugin.api import http
from livestreamer.stream import HLSStream

HLS_URL_FORMAT = "http://hls.goodgame.ru/hls/{0}{1}.m3u8"
API_URL_FORMAT = "http://api2.goodgame.ru/streams/{0}"
QUALITIES = {
    "1080p": "",
    "720p": "_720",
    "480p": "_480",
    "240p": "_240"
}

_url_re = re.compile("https?://(?:www\.)?goodgame.ru/channel/(?P<user>\w+)")
_stream_re = re.compile(
    "\"gg_player_src\":\"(\w+)\""
)

class GoodGame(Plugin):
    @classmethod

    def can_handle_url(self, url):
        return _url_re.match(url)

    def _check_stream(self, url):
        res = http.get(url, acceptable_status=(200, 404))
        if res.status_code == 200:
            return True

    def _get_streams(self):
        match = _url_re.search(self.url)
        id = match.group(1)
        url = API_URL_FORMAT.format(id)
        res = http.get(url)
        match = _stream_re.search(res.text)
        if not match:
            return

        stream_id = match.group(1)
        streams = {}
        for name, url_suffix in QUALITIES.items():
            url = HLS_URL_FORMAT.format(stream_id, url_suffix)
            if not self._check_stream(url):
                continue

            streams[name] = HLSStream(self.session, url)
        return streams

__plugin__ = GoodGame
```
https://github.com/chrippa/livestreamer/issues/1518
https://yadi.sk/d/-MA5GdyrxbmN7 - my plugin for livestreamer
Streamlink is a fork of the dead Livestreamer project. Anything that's included in Livestreamer is outdated and not really worth mentioning. If the modifications here are causing a plugin to not work again, then it's probably caused by something else.

Your suggested plugin code is from 1699e4159f6ba2049d29c4e25f1a60c6cb7f33b0, which has seen a lot of changes since then:
https://github.com/streamlink/streamlink/commits/master/src/streamlink/plugins/goodgame.py
https://github.com/streamlink/streamlink/blame/master/src/streamlink/plugins/goodgame.py

If you have further improvement suggestions, please open a pull request instead of linking external code, so it can be properly reviewed and possibly even merged. Thanks

Resolving patch:
diff --git a/src/streamlink/plugins/goodgame.py b/src/streamlink/plugins/goodgame.py
--- a/src/streamlink/plugins/goodgame.py
+++ b/src/streamlink/plugins/goodgame.py
@@ -3,6 +3,7 @@
 from streamlink.plugin import Plugin
 from streamlink.plugin.api import http
 from streamlink.stream import HLSStream
+from streamlink.utils import parse_json
 
 HLS_URL_FORMAT = "https://hls.goodgame.ru/hls/{0}{1}.m3u8"
 QUALITIES = {
@@ -13,7 +14,7 @@
 }
 
 _url_re = re.compile(r"https?://(?:www\.)?goodgame.ru/channel/(?P<user>[^/]+)")
-_stream_re = re.compile(r'var src = "([^"]+)";')
+_apidata_re = re.compile(r'var\s+ApiData\s*=\s*({.*?})\s*;', re.MULTILINE)
 _ddos_re = re.compile(r'document.cookie="(__DDOS_[^;]+)')
 
 
@@ -35,17 +36,19 @@ def _get_streams(self):
 
         match = _ddos_re.search(res.text)
         if match:
+            self.logger.debug("Anti-DDOS bypass...")
             headers["Cookie"] = match.group(1)
             res = http.get(self.url, headers=headers)
 
-        match = _stream_re.search(res.text)
+        match = _apidata_re.search(res.text)
         if not match:
             return
 
-        stream_id = match.group(1)
+        stream_data = parse_json(match.group(1))
+        self.logger.debug("Found channel info for {channel_key}", **stream_data)
         streams = {}
         for name, url_suffix in QUALITIES.items():
-            url = HLS_URL_FORMAT.format(stream_id, url_suffix)
+            url = HLS_URL_FORMAT.format(stream_data["channel_id"], url_suffix)
             if not self._check_stream(url):
                 continue
 


Test patch: