Repository: streamlink/streamlink
Pull request #123 (2016-11-03 15:32:56)

TVPlayer.com: fix for 400 error, correctly set the platform parameter
The User-Agent header needs to be sent for the page to fill in the correct platform variable. 

codecov-io: ## [Current coverage](https://codecov.io/gh/streamlink/streamlink/pull/123?src=pr) is 33.28% (diff: 100%)
> Merging [#123](https://codecov.io/gh/streamlink/streamlink/pull/123?src=pr) into [master](https://codecov.io/gh/streamlink/streamlink/branch/master?src=pr) will not change coverage

```diff
@@             master       #123   diff @@
==========================================
  Files            39         39          
  Lines          5315       5315          
  Methods           0          0          
  Messages          0          0          
  Branches          0          0          
==========================================
  Hits           1769       1769          
  Misses         3546       3546          
  Partials          0          0          
```

> Powered by [Codecov](https://codecov.io?src=pr). Last update [d20d1a6...45264ee](https://codecov.io/gh/streamlink/streamlink/compare/d20d1a62b53fc49aab6c9df3bc52020ee77ae607...45264ee0f92e7cdef4eb15227e19b43d52bde98f?src=pr)

Patch:
diff --git a/src/streamlink/plugins/livecodingtv.py b/src/streamlink/plugins/livecodingtv.py
index b5ad3a08..74522af7 100644
--- a/src/streamlink/plugins/livecodingtv.py
+++ b/src/streamlink/plugins/livecodingtv.py
@@ -1,12 +1,20 @@
 import re
 from streamlink.plugin import Plugin
+from streamlink.stream import HLSStream
 from streamlink.stream import RTMPStream, HTTPStream
 from streamlink.plugin.api import http
 
 
-_vod_re = re.compile('\"(http(s)?://.*\.mp4\?t=.*)\"')
-_rtmp_re = re.compile('rtmp://[^"]+/(?P<channel>\w+)+[^/"]+')
-_url_re = re.compile('http(s)?://(?:\w+.)?\livecoding\.tv')
+_streams_re = re.compile(r"""
+    src:\s+"(
+        rtmp://.*?\?t=.*?|                      # RTMP stream
+        https?://.*?playlist.m3u8.*?\?t=.*?|    # HLS stream
+        https?://.*?manifest.mpd.*?\?t=.*?|     # DASH stream
+        https?://.*?.mp4\?t=.*?                 # HTTP stream
+        )".*?
+     type:\s+"(.*?)"                            # which stream type it is
+     """, re.M | re.DOTALL | re.VERBOSE)
+_url_re = re.compile(r"http(s)?://(?:\w+\.)?livecoding\.tv")
 
 
 class LivecodingTV(Plugin):
@@ -16,18 +24,19 @@ class LivecodingTV(Plugin):
 
     def _get_streams(self):
         res = http.get(self.url)
-        match = _rtmp_re.search(res.content.decode('utf-8'))
-        if match:
-            params = {
-                "rtmp": match.group(0),
-                "pageUrl": self.url,
-                "live": True,
-            }
-            yield 'live', RTMPStream(self.session, params)
-            return
-
-        match = _vod_re.search(res.content.decode('utf-8'))
-        if match:
-            yield 'vod', HTTPStream(self.session, match.group(1))
+        match = _streams_re.findall(res.content.decode('utf-8'))
+        for url, stream_type in match:
+            if stream_type == "rtmp/mp4" and RTMPStream.is_usable(self.session):
+                params = {
+                    "rtmp": url,
+                    "pageUrl": self.url,
+                    "live": True,
+                }
+                yield 'live', RTMPStream(self.session, params)
+            elif stream_type == "application/x-mpegURL":
+                for s in HLSStream.parse_variant_playlist(self.session, url).items():
+                    yield s
+            elif stream_type == "video/mp4":
+                yield 'vod', HTTPStream(self.session, url)
 
 __plugin__ = LivecodingTV
diff --git a/src/streamlink/plugins/tvplayer.py b/src/streamlink/plugins/tvplayer.py
index ffe8f191..a16d6d34 100644
--- a/src/streamlink/plugins/tvplayer.py
+++ b/src/streamlink/plugins/tvplayer.py
@@ -11,7 +11,7 @@ class TVPlayer(Plugin):
         "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) "
         "Chrome/43.0.2357.65 Safari/537.36")
     API_URL = "http://api.tvplayer.com/api/v2/stream/live"
-    _url_re = re.compile(r"http://(?:www.)?tvplayer.com/watch/(.+)")
+    _url_re = re.compile(r"https?://(?:www.)?tvplayer.com/(:?watch/?|watch/(.+)?)")
     _stream_attrs_ = re.compile(r'var\s+(validate|platform|resourceId)\s+=\s*(.*?);', re.S)
     _stream_schema = validate.Schema({
         "tvplayer": validate.Schema({
@@ -25,11 +25,12 @@ class TVPlayer(Plugin):
     @classmethod
     def can_handle_url(cls, url):
         match = TVPlayer._url_re.match(url)
-        return match
+        return match is not None
 
     def _get_streams(self):
         # find the list of channels from the html in the page
-        res = http.get(self.url)
+        self.url = self.url.replace("https", "http")  # https redirects to http
+        res = http.get(self.url, headers={"User-Agent": TVPlayer._user_agent})
         stream_attrs = dict((k, v.strip('"')) for k, v in TVPlayer._stream_attrs_.findall(res.text))
 
         # get the stream urls


Test patch:
diff --git a/tests/test_plugin_tvplayer.py b/tests/test_plugin_tvplayer.py
new file mode 100644
index 00000000..b3f1a6a3
--- /dev/null
+++ b/tests/test_plugin_tvplayer.py
@@ -0,0 +1,21 @@
+import unittest
+
+from streamlink.plugins.tvplayer import TVPlayer
+
+
+class TestPluginTVPlayer(unittest.TestCase):
+    def test_can_handle_url(self):
+        # should match
+        self.assertTrue(TVPlayer.can_handle_url("http://tvplayer.com/watch/"))
+        self.assertTrue(TVPlayer.can_handle_url("http://www.tvplayer.com/watch/"))
+        self.assertTrue(TVPlayer.can_handle_url("http://tvplayer.com/watch"))
+        self.assertTrue(TVPlayer.can_handle_url("http://www.tvplayer.com/watch"))
+        self.assertTrue(TVPlayer.can_handle_url("http://tvplayer.com/watch/dave"))
+        self.assertTrue(TVPlayer.can_handle_url("http://www.tvplayer.com/watch/itv"))
+        self.assertTrue(TVPlayer.can_handle_url("https://www.tvplayer.com/watch/itv"))
+        self.assertTrue(TVPlayer.can_handle_url("https://tvplayer.com/watch/itv"))
+
+        # shouldn't match
+        self.assertFalse(TVPlayer.can_handle_url("http://www.tvplayer.com/"))
+        self.assertFalse(TVPlayer.can_handle_url("http://www.tvcatchup.com/"))
+        self.assertFalse(TVPlayer.can_handle_url("http://www.youtube.com/"))