Repository: streamlink/streamlink

Issue:
Issue Capturing Some Chaturbate Models
### Checklist

- [x] This is a bug report.
- [ ] This is a plugin request.
- [ ] This is a feature request.
- [x] I used the search function to find already opened/closed issues or pull requests.

### Description

Issue when recording some models from Chaturbate. I can view models just fine but when trying to use streamlink I get an error(in the logs section). Doing a bit of playing around I have noticed that if I try from the US it does work fine. I believe this is due to CB using a different edge server. All models that I have an issue with seem to be on the edge55 server. Not sure if this is a CB issue, but due to the fact that I can view the same models as normal i think this may be an issue with the plugin.

### Expected / Actual behavior

Models don't record when they should.

### Reproduction steps / Stream URLs to test

1. http://chaturbate.com/ellieleen/
2. http://chaturbate.com/squirtbetty/
3. http://chaturbate.com/caylin/

### Environment details (operating system, python version, etc.)

Tried on Debian and Server 2012 with the same result. Also tried with python 2.7 and 3.5

### Comments, logs, screenshots, etc.

[Streamlink for Windows v0.3.2 - Git b89d4a0]
[cli][info] Found matching plugin chaturbate for URL https://chaturbate.com/elli
eleen/
error: Unable to open URL: https://edge55.stream.highwebmedia.com/live-edge/elli
eleen-sd-59241ab9b0a5237d2885fb6d5786a58c87ab56e07868db0e2e17ccc97451f0af_fast_a
ac/playlist.m3u8 (502 Server Error: Bad Gateway for url: https://edge55.stream.h
ighwebmedia.com/live-edge/ellieleen-sd-59241ab9b0a5237d2885fb6d5786a58c87ab56e07
868db0e2e17ccc97451f0af_fast_aac/playlist.m3u8)
[End of Streamlink for Windows]



Discussion:
Why not to add support to rtmp by priority and to ship K-S-V rtmpdump along with all Windows builds ?
@karlo,

I suggest other solution:

set your own path, no need to pack extras with streamlink.


C:\>path
PATH=C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\P\STREAMLINK
\bin;C:\AP;C:\AP\CURL;C:\AP\7Z;C:\AP\FF;C:\AP\RDUMP;C:\P\M;C:\P\VLC



There are number of ways to do that, one is making registry patch ( restart PC after applying the patch ):


Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Environment]
"PATH"="C:\\AP;C:\\AP\\CURL;C:\\AP\\7Z;C:\\AP\\FF;C:\\AP\\RDUMP;C:\\P\\M;C:\\P\\VLC"

support to rtmp by priority is already there,
the problem is streamlink still does not see rtmp stream on filmon.com.

Stream options:
   --stream-types TYPES, --stream-priority TYPES
    A comma-delimited list of stream types to allow.
    
    The order will be used to separate streams when there are multiple
    streams with the same name but different stream types.
    
    Default is "rtmp,hls,hds,http,akamaihd".
    


C:\>streamlink --stream-url http://www.filmon.com/channel/bbc-news best
http://edge-1273-de-fr.filmon.com/live/27.high.stream/playlist.m3u8?id=035bca1a71b11fce016d28acd3dbea51cbc96ddfe5b9ed3f8
fe3286df6a738d3e46fd0aa6eb035753c5b95150828ac01628b2b6d0d9ff1702708aa24b7987ec409b485865e24cb2636dd43dacaa8a18e4f7310fd1
6202b81b5d6e49766403d988a3f15f8a45b0929dc2c491239fc328584074ceaf5a3ef8b1bf64714c3b909047a541e472ea179cb41a90c5847362d83a
328519b78b1da92






C:\>curl -s http://www.filmon.com/api-v2/channel/27?protocol=rtmp
{"code":200,"message":"OK","data":{"id":27,"title":"BBC News","alias":"bbc-news","description":"The BBC's 24-hour news a
nd information channel that features the most up-to-date news, interviews, business reports, sports results, and weather
. Plus, catch the best of the BBC's award-winning current affairs, documentary, and lifestyle programming. ","group":"UK
 LIVE TV","group_id":5,"group_alias":"uk-live-tv","type":"standard","is_free":false,"is_free_sd_mode":true,"is_adult":fa
lse,"is_interactive":false,"is_vod":false,"is_vox":false,"is360":false,"watch_free_time":45,"is_local":true,"seekable":f
alse,"user_subscribed":false,"streams":[{"is_free":false,"name":"27.low.stream","quality":"low","url":"rtmp://edge-1273-
de-fr.filmon.com/live/?id=035bca1a71b11fce016d28acd3dbea51cbc96ddfe5b9ed3f8fe3286df6a738d3cc97988679340a507e7113071aa75d
35ecdded9a4949e9d75f11bd6f8eb3b37ae5d5c362e41d05eb1e91dbf293480410f63f2adbb3a2fb11c24633d1954868d0ab8e524a8bb4296d78218c
69eb8f4dd1a8c7596d1f2d0fcb295f3ad0cc0f993e031c860fae51d9105e4c37c12b99b3fa6cd2b56bf7acc109","watch-timeout":86500},{"is_
free":false,"name":"27.high.stream","quality":"high","url":"rtmp://edge-1273-de-fr.filmon.com/live/?id=035bca1a71b11fce0
16d28acd3dbea51cbc96ddfe5b9ed3f8fe3286df6a738d3e46fd0aa6eb0357551234ab847df915bad61fe60c83cc2e4767786d1e2d78f22d0cb25a9f
aafd92b16e14e2e74e5864208dc5fab7b01a6fb0bab35dedc912c2537f67020381d2fef21751e9dadaf6c3d67b073854beaad0e8b41e2fe98796c27e
d9954a003f60a96a54623dc8aa05d08eb8d33350013bb6c","watch-timeout":45}],"server_time":1489671692,"jwplatform_media_id":"Tc
NjQJcg","is_favorite":false}}
C:\>
@rykorb 

http://stream-recorder.com/forum/showpost.php?p=90361&postcount=20

Resolving patch:
diff --git a/src/streamlink/plugins/chaturbate.py b/src/streamlink/plugins/chaturbate.py
--- a/src/streamlink/plugins/chaturbate.py
+++ b/src/streamlink/plugins/chaturbate.py
@@ -1,37 +1,53 @@
 import re
+import uuid
 
 from streamlink.plugin import Plugin
-from streamlink.plugin.api import http, validate
+from streamlink.plugin.api import http
+from streamlink.plugin.api import validate
 from streamlink.stream import HLSStream
 
-_url_re = re.compile(r"http(s)?://(\w+.)?chaturbate.com/[^/?&]+")
-_playlist_url_re = re.compile(r"var hlsSource\w+ = '(?P<url>[^']+)';")
-_schema = validate.Schema(
-    validate.transform(_playlist_url_re.search),
-    validate.any(
-        None,
-        validate.all(
-            validate.get("url"),
-            validate.url(
-                scheme="http",
-                path=validate.endswith(".m3u8")
-            )
-        )
-    )
+API_HLS = "https://chaturbate.com/get_edge_hls_url_ajax/"
+
+_url_re = re.compile(r"https?://(\w+\.)?chaturbate\.com/(?P<username>\w+)")
+
+_post_schema = validate.Schema(
+    {
+        "url": validate.text,
+        "room_status": validate.text,
+        "success": int
+    }
 )
 
 
 class Chaturbate(Plugin):
     @classmethod
-    def can_handle_url(self, url):
+    def can_handle_url(cls, url):
         return _url_re.match(url)
 
     def _get_streams(self):
-        playlist_url = http.get(self.url, schema=_schema)
-        if not playlist_url:
-            return
+        match = _url_re.match(self.url)
+        username = match.group("username")
+
+        CSRFToken = str(uuid.uuid4().hex.upper()[0:32])
+
+        headers = {
+            "Content-Type": "application/x-www-form-urlencoded",
+            "X-CSRFToken": CSRFToken,
+            "X-Requested-With": "XMLHttpRequest",
+            "Referer": self.url,
+        }
+
+        cookies = {
+            "csrftoken": CSRFToken,
+        }
+
+        post_data = "room_slug={0}&bandwidth=high".format(username)
 
-        return HLSStream.parse_variant_playlist(self.session, playlist_url)
+        res = http.post(API_HLS, headers=headers, cookies=cookies, data=post_data)
+        data = http.json(res, schema=_post_schema)
 
+        if data["success"] is True and data["room_status"] == "public":
+            for s in HLSStream.parse_variant_playlist(self.session, data["url"]).items():
+                yield s
 
 __plugin__ = Chaturbate


Test patch:
diff --git a/tests/test_plugin_chaturbate.py b/tests/test_plugin_chaturbate.py
new file mode 100644
--- /dev/null
+++ b/tests/test_plugin_chaturbate.py
@@ -0,0 +1,15 @@
+import unittest
+
+from streamlink.plugins.chaturbate import Chaturbate
+
+
+class TestPluginChaturbate(unittest.TestCase):
+    def test_can_handle_url(self):
+        # should match
+        self.assertTrue(Chaturbate.can_handle_url("https://chaturbate.com/username"))
+        self.assertTrue(Chaturbate.can_handle_url("https://m.chaturbate.com/username"))
+        self.assertTrue(Chaturbate.can_handle_url("https://www.chaturbate.com/username"))
+
+        # shouldn't match
+        self.assertFalse(Chaturbate.can_handle_url("http://local.local/"))
+        self.assertFalse(Chaturbate.can_handle_url("http://localhost.localhost/"))