Repository: streamlink/streamlink

Issue:
vrt.nu plugin: doesnt works anymore
### Checklist

- [x] This is a bug report.
- [ ] This is a feature request.
- [ ] This is a plugin (improvement) request.
- [x] I have read the contribution guidelines.

### Description
vrt.nu (Belgian Flemish television) plugin doesnt works anymore

### Expected / Actual behavior
is there a way to fix this issue ?

### Reproduction steps / Explicit stream URLs to test
1.  type command in terminal: `streamlink https://www.vrt.be/vrtnu/kanalen/een/ best`

### Logs
https://paste.ubuntu.com/p/PcTCH29Pq7/

### Environment details
  - OS                    : Ubuntu 18.04 bionic 32bits
  - Python version : 3.6.5
  - Streamlink        : 0.13.0


Discussion:

Resolving patch:
diff --git a/src/streamlink/plugins/vrtbe.py b/src/streamlink/plugins/vrtbe.py
--- a/src/streamlink/plugins/vrtbe.py
+++ b/src/streamlink/plugins/vrtbe.py
@@ -1,85 +1,92 @@
+import logging
 import re
 
+from streamlink.compat import urljoin
 from streamlink.plugin import Plugin
-from streamlink.plugin.api import http
 from streamlink.plugin.api import validate
-from streamlink.stream import HDSStream
-from streamlink.stream import HLSStream
-from streamlink.utils import parse_json
+from streamlink.plugin.api.utils import itertags
+from streamlink.stream import HLSStream, DASHStream
 
-_url_re = re.compile(r'''https?://www\.vrt\.be/vrtnu/(?:kanalen/(?P<channel>[^/]+)|\S+)''')
-_json_re = re.compile(r'''(\173[^\173\175]+\175)''')
+log = logging.getLogger(__name__)
 
-API_LIVE = 'https://services.vrt.be/videoplayer/r/live.json'
-API_VOD = 'https://mediazone.vrt.be/api/v1/{0}/assets/{1}'
 
-_stream_schema = validate.Schema({
-    'targetUrls': [
-        {
-            'type': validate.text,
-            'url': validate.text
+class VRTbe(Plugin):
+    _url_re = re.compile(r'''https?://www\.vrt\.be/vrtnu/(?:kanalen/(?P<channel>[^/]+)|\S+)''')
+
+    _stream_schema = validate.Schema(
+        validate.any({
+            "code": validate.text,
+            "message": validate.text
         },
-    ],
-})
+        {
+            "drm": validate.any(None, validate.text),
+            'targetUrls': [{
+                'type': validate.text,
+                'url': validate.text
+            }],
+        })
+    )
 
+    _token_schema = validate.Schema({
+        "vrtPlayerToken": validate.text
+    }, validate.get("vrtPlayerToken"))
+
+    api_url = "https://api.vuplay.co.uk/"
 
-class VRTbe(Plugin):
     @classmethod
     def can_handle_url(cls, url):
-        return _url_re.match(url)
+        return cls._url_re.match(url)
 
-    def _get_live_stream(self, channel):
-        channel = 'vualto_{0}'.format(channel)
-        _live_json_re = re.compile(r'''"{0}":\s(\173[^\173\175]+\175)'''.format(channel))
+    def _get_api_info(self, page):
+        for div in itertags(page.text, 'div'):
+            if div.attributes.get("class") == "vrtvideo":
+                api_base = div.attributes.get("data-mediaapiurl") + "/"
 
-        res = http.get(API_LIVE)
-        match = _live_json_re.search(res.text)
-        if not match:
-            return
-        data = parse_json(match.group(1))
+                data = {"token_url": urljoin(api_base, "tokens")}
+                if div.attributes.get("data-videotype") == "live":
+                    data["stream_url"] = urljoin(urljoin(api_base, "videos/"), div.attributes.get("data-livestream"))
+                else:
+                    resource = "{0}%24{1}".format(div.attributes.get("data-publicationid"), div.attributes.get("data-videoid"))
+                    data["stream_url"] = urljoin(urljoin(api_base, "videos/"), resource)
+                return data
 
-        hls_url = data['hls']
+    def _get_streams(self):
+        page = self.session.http.get(self.url)
+        api_info = self._get_api_info(page)
 
-        if hls_url:
-            for s in HLSStream.parse_variant_playlist(self.session, hls_url).items():
-                yield s
+        if not api_info:
+            log.error("Could not find API info in page")
+            return
 
-    def _get_vod_stream(self):
-        vod_url = self.url
-        if vod_url.endswith('/'):
-            vod_url = vod_url[:-1]
+        token_res = self.session.http.post(api_info["token_url"])
+        token = self.session.http.json(token_res, schema=self._token_schema)
 
-        json_url = '{0}.securevideo.json'.format(vod_url)
+        log.debug("Got token: {0}".format(token))
+        log.debug("Getting stream data: {0}".format(api_info["stream_url"]))
+        res = self.session.http.get(api_info["stream_url"],
+                                    params={
+                                        "vrtPlayerToken": token,
+                                        "client": "vrtvideo"
+                                    }, raise_for_status=False)
+        data = self.session.http.json(res, schema=self._stream_schema)
 
-        res = http.get(json_url)
-        match = _json_re.search(res.text)
-        if not match:
+        if "code" in data:
+            log.error("{0} ({1})".format(data['message'], data['code']))
             return
-        data = parse_json(match.group(1))
 
-        res = http.get(API_VOD.format(data['clientid'], data['mzid']))
-        data = http.json(res, schema=_stream_schema)
+        log.debug("Streams have {0}DRM".format("no " if not data["drm"] else ""))
 
-        for d in data['targetUrls']:
-            if d['type'] == 'HDS':
-                hds_url = d['url']
-                for s in HDSStream.parse_manifest(self.session, hds_url).items():
+        for target in data["targetUrls"]:
+            if data["drm"]:
+                if target["type"] == "hls_aes":
+                    for s in HLSStream.parse_variant_playlist(self.session, target["url"]).items():
+                        yield s
+            elif target["type"] == "hls":
+                for s in HLSStream.parse_variant_playlist(self.session, target["url"]).items():
                     yield s
-
-            if d['type'] == 'HLS':
-                hls_url = d['url']
-                for s in HLSStream.parse_variant_playlist(self.session, hls_url).items():
+            elif target["type"] == "mpeg_dash":
+                for s in DASHStream.parse_manifest(self.session, target["url"]).items():
                     yield s
 
-    def _get_streams(self):
-        match = _url_re.match(self.url)
-
-        channel = match.group('channel')
-
-        if channel:
-            return self._get_live_stream(channel)
-        else:
-            return self._get_vod_stream()
-
 
 __plugin__ = VRTbe
diff --git a/src/streamlink/stream/dash_manifest.py b/src/streamlink/stream/dash_manifest.py
--- a/src/streamlink/stream/dash_manifest.py
+++ b/src/streamlink/stream/dash_manifest.py
@@ -488,7 +488,7 @@ def format_media(self, **kwargs):
             else:
                 for segment, n in zip(self.segmentTimeline.segments, count(self.startNumber)):
                     yield (self.make_url(self.media(Time=segment.t, Number=n, **kwargs)),
-                           datetime.timedelta(seconds=segment.d / self.timescale))
+                           datetime.datetime.now(tz=utc))
 
         else:
             for number, available_at in self.segment_numbers():


Test patch: