From dc95ccf7cf7392d59a4adcce3b5fee6e27e86fdf Mon Sep 17 00:00:00 2001 From: back-to Date: Wed, 5 Apr 2017 20:11:05 +0000 Subject: [PATCH 1/2] [chaturbate] New API for HLS url --- src/streamlink/plugins/chaturbate.py | 56 ++++++++++++++++++---------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/src/streamlink/plugins/chaturbate.py b/src/streamlink/plugins/chaturbate.py index 1e59482b..bbdeddea 100644 --- 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[^']+)';") -_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\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") - return HLSStream.parse_variant_playlist(self.session, playlist_url) + CSRFToken = str(uuid.uuid4().get_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) + + 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 From 277d064051e9166f61df315ae04cc71011a61e98 Mon Sep 17 00:00:00 2001 From: back-to Date: Fri, 7 Apr 2017 12:10:48 +0000 Subject: [PATCH 2/2] [chaturbate] Fixed python 3.5 bug and added regex tests --- src/streamlink/plugins/chaturbate.py | 2 +- tests/test_plugin_chaturbate.py | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/test_plugin_chaturbate.py diff --git a/src/streamlink/plugins/chaturbate.py b/src/streamlink/plugins/chaturbate.py index bbdeddea..4820db3a 100644 --- a/src/streamlink/plugins/chaturbate.py +++ b/src/streamlink/plugins/chaturbate.py @@ -28,7 +28,7 @@ class Chaturbate(Plugin): match = _url_re.match(self.url) username = match.group("username") - CSRFToken = str(uuid.uuid4().get_hex().upper()[0:32]) + CSRFToken = str(uuid.uuid4().hex.upper()[0:32]) headers = { "Content-Type": "application/x-www-form-urlencoded", diff --git a/tests/test_plugin_chaturbate.py b/tests/test_plugin_chaturbate.py new file mode 100644 index 00000000..a9542a33 --- /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/"))