Repository: streamlink/streamlink

Issue:
Add plugin: yupptv
I am suspecting that cookies/token expires and I am no longer able to play the stream, not even a restart as it returns **`403 Client Error: Forbidden`**

Example of the links I am getting:

`http://hlsbanglanews-lh.akamaihd.net/i/ams54_russiatoday@349571/master.m3u8?hdnea=st%3d1485750135%7eexp%3d1485750495%7eacl%3d%2fi%2fams54_russiatoday%40349571%2f*%7edata%3d1814225%7ehmac%3da3a3c4227a1c121aca77c38e9c21252bd881a5a9d5c96d7851ac8f53bb56c2a7&dw=160`

Streaming url: 

`http://hlsbanglanews-lh.akamaihd.net/i/ams54_russiatoday@349571/master.m3u8`
Token?:

`hdnea=st%3d1485750135%7eexp%3d1485750495%7eacl%3d%2fi%2fams54_russiatoday%40349571%2f*%7edata%3d1814225%7ehmac%3da3a3c4227a1c121aca77c38e9c21252bd881a5a9d5c96d7851ac8f53bb56c2a7&dw=160`

Seems like there is linux epoch time that sets the expiry of the stream. So each time i need to login to the website and request new token.

I also know the following:
SWF: `http://d3hprka3kr08q2.cloudfront.net/staticstorage/jwplayer/jw_7_8_2/jwplayer.loader.swf`


Content of M3U8 file: 

```
#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=87000,RESOLUTION=256x144,CODECS="avc1.66.30, mp4a.40.2"
http://hlsbanglanews-lh.akamaihd.net/i/ams54_russiatoday@349571/index_64_av-p.m3u8?sd=10&dw=160&rebase=on&hdntl=exp=1485836971~acl=%2fi%2fams54_russiatoday%40349571%2f*~data=hdntl~hmac=a18a639e66837c960067f07eae81b129b3d20804fd69aaec598f138ab9321128
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=226000,RESOLUTION=384x216,CODECS="avc1.66.30, mp4a.40.2"
http://hlsbanglanews-lh.akamaihd.net/i/ams54_russiatoday@349571/index_200_av-p.m3u8?sd=10&dw=160&rebase=on&hdntl=exp=1485836971~acl=%2fi%2fams54_russiatoday%40349571%2f*~data=hdntl~hmac=a18a639e66837c960067f07eae81b129b3d20804fd69aaec598f138ab9321128
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=403000,RESOLUTION=480x270,CODECS="avc1.66.30, mp4a.40.2"
http://hlsbanglanews-lh.akamaihd.net/i/ams54_russiatoday@349571/index_400_av-p.m3u8?sd=10&dw=160&rebase=on&hdntl=exp=1485836971~acl=%2fi%2fams54_russiatoday%40349571%2f*~data=hdntl~hmac=a18a639e66837c960067f07eae81b129b3d20804fd69aaec598f138ab9321128
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=647000,RESOLUTION=512x288,CODECS="avc1.66.30, mp4a.40.2"
http://hlsbanglanews-lh.akamaihd.net/i/ams54_russiatoday@349571/index_800_av-p.m3u8?sd=10&dw=160&rebase=on&hdntl=exp=1485836971~acl=%2fi%2fams54_russiatoday%40349571%2f*~data=hdntl~hmac=a18a639e66837c960067f07eae81b129b3d20804fd69aaec598f138ab9321128
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=1233000,RESOLUTION=704x396,CODECS="avc1.66.30, mp4a.40.2"
http://hlsbanglanews-lh.akamaihd.net/i/ams54_russiatoday@349571/index_1100_av-p.m3u8?sd=10&dw=160&rebase=on&hdntl=exp=1485836971~acl=%2fi%2fams54_russiatoday%40349571%2f*~data=hdntl~hmac=a18a639e66837c960067f07eae81b129b3d20804fd69aaec598f138ab9321128
```

Also, few attributes such as "Referer" for the m3u8 stream.

Is it possible to somehow automate via streamlink the token request process? The website does require a log on in order to get the stream link.


Discussion:
You will almost certainly need a plugin to do this. What is the website? 

Normally the Akamai HLS streams set a long token cookie, but there have been some streams where the long token doesn't work for the playlist. Not much you can do expect create a plugin to support the site. 
yupptv.com
How would I go about seeking help for the plugin? Not even sure where to look and who to ask...?

Thank you,
You can request one here :-)
Would it need to be as a new ticket?
Just update the title of this one :)
Done :)
Is there plugin for it to download:)
Can some help how to make plugin for it
anyluck with  yupptv.com plugin


Resolving patch:
diff --git a/src/streamlink/plugins/yupptv.py b/src/streamlink/plugins/yupptv.py
new file mode 100644
--- /dev/null
+++ b/src/streamlink/plugins/yupptv.py
@@ -0,0 +1,84 @@
+import logging
+import re
+
+from streamlink import PluginError
+from streamlink.plugin import Plugin, PluginArguments, PluginArgument
+from streamlink.plugin.api import http, useragents
+from streamlink.stream import HLSStream
+
+
+
+log = logging.getLogger(__name__)
+
+
+class YuppTV(Plugin):
+    _url_re = re.compile(r"""https?://(?:www\.)?yupptv\.com""", re.VERBOSE)
+    _m3u8_re = re.compile(r'''['"](http.+\.m3u8.*?)['"]''')
+    _login_url = "https://www.yupptv.com/auth/validateSignin"
+    _box_logout = "https://www.yupptv.com/auth/confirmLogout"
+    _signin_url = "https://www.yupptv.com/signin/"
+    _account_url = "https://www.yupptv.com/account/myaccount.aspx"
+
+    arguments = PluginArguments(
+        PluginArgument(
+            "email",
+            requires=["password"],
+            metavar="EMAIL",
+            help="Your YuppTV account email"
+        ),
+        PluginArgument(
+            "password",
+            sensitive=True,
+            metavar="PASSWORD",
+            help="Your YuppTV account password."
+        )
+    )
+
+    @classmethod
+    def can_handle_url(cls, url):
+        return cls._url_re.match(url) is not None
+
+    def login(self, username, password, depth=3):
+        if depth == 0:
+            log.error("Failed to login to YuppTV")
+            raise PluginError("cannot login")
+
+        res = http.post(self._login_url, data=dict(user=username, password=password, isMobile=0), headers={"Referer": self._signin_url})
+        data = http.json(res)
+        resp = data['Response']
+        if resp["tempBoxid"]:
+            # log out on other device
+            log.info("Logging out on other device: {0}".format(resp["tempBoxid"]))
+            _ = http.get(self._box_logout, params=dict(boxId=resp["tempBoxid"]))
+            return self.login(username, password, depth-1)
+        return resp['errorCode'], resp['statusmsg']
+
+    def _get_streams(self):
+        http.headers.update({"User-Agent": useragents.CHROME})
+
+        if self.get_option("email") and self.get_option("password"):
+            error_code, error_msg = self.login(self.get_option("email"), self.get_option("password"))
+            if error_code is None:
+                log.info("Logged in as {0}".format(self.get_option("email")))
+            else:
+                log.error("Failed to login: {1} (code: {0})".format(error_code, error_msg))
+
+        page = http.get(self.url)
+        match = self._m3u8_re.search(page.text)
+        if match:
+            stream_url = match.group(1)
+            if "preview/" in stream_url:
+                if "btnsignup" in page.text:
+                    log.error("This stream requires you to login")
+                else:
+                    log.error("This stream requires a subscription")
+                return
+
+            return HLSStream.parse_variant_playlist(self.session, stream_url)
+        elif "btnsignup" in page.text:
+            log.error("This stream requires you to login")
+        elif "btnsubscribe" in page.text:
+            log.error("This stream requires a subscription")
+
+
+__plugin__ = YuppTV


Test patch:
diff --git a/tests/test_plugin_yupptv.py b/tests/test_plugin_yupptv.py
new file mode 100644
--- /dev/null
+++ b/tests/test_plugin_yupptv.py
@@ -0,0 +1,15 @@
+import unittest
+
+from streamlink.plugins.yupptv import YuppTV
+
+
+class TestPluginZattoo(unittest.TestCase):
+    def test_can_handle_url(self):
+        self.assertTrue(YuppTV.can_handle_url('https://www.yupptv.com/channels/etv-telugu/live'))
+        self.assertTrue(YuppTV.can_handle_url('https://www.yupptv.com/channels/india-today-news/news/25326023/15-jun-2018'))
+
+    def test_can_handle_negative(self):
+        # shouldn't match
+        self.assertFalse(YuppTV.can_handle_url('https://ewe.de'))
+        self.assertFalse(YuppTV.can_handle_url('https://netcologne.de'))
+        self.assertFalse(YuppTV.can_handle_url('https://zattoo.com'))