Repository: streamlink/streamlink
Pull request #2267 (2019-01-24 14:38:04)

plugins.ustreamtv: handle stream names better, allow '_alt' streams
`preset` might be a duplicate of `original` use `videoCodec height` instead.

```
{'segmentUrl': '2/4/chunk_%_%.flv', 'bitrate': 2561, 'preset': 'original', 'transcoded': False, 'videoCodec': {'height': 720}}
{'segmentUrl': '2/9/chunk_%_%.flv', 'bitrate': 2556, 'preset': 'original', 'transcoded': False, 'videoCodec': {'height': 720}}
{'segmentUrl': '5/4/chunk_%_%.flv', 'bitrate': 312, 'preset': 'original', 'transcoded': False, 'videoCodec': {'height': 486}}
{'segmentUrl': '5/9/chunk_%_%.flv', 'bitrate': 307, 'preset': 'original', 'transcoded': False, 'videoCodec': {'height': 486}}
{'segmentUrl': '8/4/chunk_%_%.flv', 'bitrate': 243, 'preset': '360p', 'transcoded': True, 'videoCodec': {'height': 360}}
{'segmentUrl': '8/9/chunk_%_%.flv', 'bitrate': 238, 'preset': '360p', 'transcoded': True, 'videoCodec': {'height': 360}}
{'segmentUrl': '6/4/chunk_%_%.flv', 'bitrate': 186, 'preset': 'original', 'transcoded': False, 'videoCodec': {'height': 252}}
{'segmentUrl': '6/9/chunk_%_%.flv', 'bitrate': 181, 'preset': 'original', 'transcoded': False, 'videoCodec': {'height': 252}}
```

before

```
$ streamlink https://www.ustream.tv/nasahdtv best -l info
[cli][info] Found matching plugin ustreamtv for URL https://www.ustream.tv/nasahdtv
[cli][info] Available streams: 360p (worst), original (best)
[cli][info] Opening stream: original (uhs)
```

after

```
$ streamlink https://www.ustream.tv/nasahdtv best -l info
[cli][info] Found matching plugin ustreamtv for URL https://www.ustream.tv/nasahdtv
[cli][info] Available streams: 252p_alt (worst), 252p, 360p_alt, 360p, 486p_alt, 486p, 720p_alt, 720p (best)
[cli][info] Opening stream: 720p (uhs)
```

codecov[bot]: # [Codecov](https://codecov.io/gh/streamlink/streamlink/pull/2267?src=pr&el=h1) Report
> Merging [#2267](https://codecov.io/gh/streamlink/streamlink/pull/2267?src=pr&el=desc) into [master](https://codecov.io/gh/streamlink/streamlink/commit/965c375825906d07354cf6bbc9208c9933bc5156?src=pr&el=desc) will **decrease** coverage by `0.32%`.
> The diff coverage is `0%`.


```diff
@@            Coverage Diff             @@
##           master    #2267      +/-   ##
==========================================
- Coverage   52.64%   52.31%   -0.33%     
==========================================
  Files         237      237              
  Lines       14747    14746       -1     
==========================================
- Hits         7763     7715      -48     
- Misses       6984     7031      +47
```

codecov[bot]: # [Codecov](https://codecov.io/gh/streamlink/streamlink/pull/2267?src=pr&el=h1) Report
> Merging [#2267](https://codecov.io/gh/streamlink/streamlink/pull/2267?src=pr&el=desc) into [master](https://codecov.io/gh/streamlink/streamlink/commit/965c375825906d07354cf6bbc9208c9933bc5156?src=pr&el=desc) will **decrease** coverage by `0.32%`.
> The diff coverage is `0%`.


```diff
@@            Coverage Diff             @@
##           master    #2267      +/-   ##
==========================================
- Coverage   52.64%   52.31%   -0.33%     
==========================================
  Files         237      237              
  Lines       14747    14746       -1     
==========================================
- Hits         7763     7715      -48     
- Misses       6984     7031      +47
```


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8f25163a..152e00da 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,246 @@
 # Changelog
 
+## streamlink 1.0.0 (2019-01-30)
+
+The celebratory release of Streamlink 1.0.0!
+
+*A lot* of hard work has gone into getting Streamlink to where it is. Not only is Streamlink used across multiple applications and platforms, but companies as well. 
+
+Streamlink started from the inaugural [fork of Livestreamer](https://github.com/chrippa/livestreamer/issues/1427) on September 17th, 2016. 
+
+Since then, We've hit multiple milestones:
+
+ - Over 886 PRs
+ - Hit 3,000 commits in Streamlink
+ - Obtaining our first sponsors as well as backers of the project
+ - The creation of our own logo (https://github.com/streamlink/streamlink/issues/1123)
+
+Thanks to everyone who has contributed to Streamlink (and our backers)! Without you, we wouldn't be where we are today.
+
+**Without further ado, here are the changes in release 1.0.0:**
+
+  - We have a new icon / logo for Streamlink! (https://github.com/streamlink/streamlink/pull/2165)
+  - Updated dependencies (https://github.com/streamlink/streamlink/pull/2230)
+  - A *ton* of plugin updates. Have a look at [this search query](https://github.com/streamlink/streamlink/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aclosed+plugins.+) for all the recent updates.
+  - You can now provide a custom key URI to override HLS streams (https://github.com/streamlink/streamlink/pull/2139). For example: `--hls-segment-key-uri <URI>`
+  - User agents for API communication have been updated (https://github.com/streamlink/streamlink/pull/2194)
+  - Special synonyms have been added to sort "best" and "worst" streams (https://github.com/streamlink/streamlink/pull/2127). For example: `streamlink --stream-sorting-excludes '>=480p' URL best,best-unfiltered`
+  - Process output will no longer show if tty is unavailable (https://github.com/streamlink/streamlink/pull/2090)
+  - We've removed BountySource in favour of our OpenCollective page. If you have any features you'd like to request, please open up an issue with the request and possibly consider backing us!
+  - Improved terminal progress display for wide characters (https://github.com/streamlink/streamlink/pull/2032)
+  - Fixed a bug with dynamic playlists on playback (https://github.com/streamlink/streamlink/pull/2096)
+  - Fixed makeinstaller.sh (https://github.com/streamlink/streamlink/pull/2098)
+  - Old Livestreamer deprecations and API references were removed (https://github.com/streamlink/streamlink/pull/1987)
+  - Dependencies have been updated for Python (https://github.com/streamlink/streamlink/pull/1975)
+  - Newer and more common User-Agents are now used (https://github.com/streamlink/streamlink/pull/1974)
+  - DASH stream bitrates now round-up to the nearest 10, 100, 1000, etc. (https://github.com/streamlink/streamlink/pull/1995)
+  - Updated documentation on issue templates (https://github.com/streamlink/streamlink/pull/1996)
+  - URL have been added for better processing of HTML tags (https://github.com/streamlink/streamlink/pull/1675)
+  - Fixed sort and prog issue (https://github.com/streamlink/streamlink/pull/1964)
+  - Reformatted issue templates (https://github.com/streamlink/streamlink/pull/1966)
+  - Fixed crashing bug with player-continuous-http option (https://github.com/streamlink/streamlink/pull/2234)
+  - Make sure all dev dependencies (https://github.com/streamlink/streamlink/pull/2235)
+  - -r parameter has been replaced for --rtmp-rtmpdump (https://github.com/streamlink/streamlink/pull/2152)
+
+**Breaking changes:**
+
+  - A large number of unmaintained or NSFW plugins have been removed. You can find the PR that implemented that change here: https://github.com/streamlink/streamlink/pull/2003 . See our [CONTRIBUTING.md](https://github.com/streamlink/streamlink/blob/130489c6f5ad15488cd4ff7a25c74bf070f163ec/CONTRIBUTING.md) documentation for plugin policy.
+
+
+
+```text
+Billy2011 <kschmidt2007@googlemail.com> (3):
+      streamlink.plugins: replace global http session by self.session.http (#1925)
+      stream.hls_playlist: fix some regex pattern & code optimization (#1918)
+      plugins.filmon: fix NoPluginError, if channel is not an ID (#2005)
+
+David Bell <me@geordish.org> (1):
+      Update ine.py (#2171)
+
+Forrest <forrest.alvarez@protonmail.com> (2):
+      Remove bountysource from donation page, update flattr
+      Add a note about specifying the full player path
+
+Forrest <gravyboat@users.noreply.github.com> (2):
+      Feature/plugin request policy update (#1838)
+      Add icon, modify installer, update docs (#2165)
+
+Hubcapp <walnut.alligator@gmail.com> (1):
+      Window Titles = Stream Titles + Other Attributes (#1576)
+
+Jani Ollikainen <bestis@cd.purkki.org> (1):
+      Added support for viafree.fi
+
+Lukas <keydon@gmail.com> (1):
+      plugins.zdf_mediathek: use ptmd-template api path (#2233)
+
+Maxwell Cody <maxwellcody@riseup.net> (1):
+      Add ability to specify custom key URI override for HLS streams (#2139)
+
+Mohamed El Morabity <melmorabity@users.noreply.github.com> (1):
+      plugins.pluzz: fixes and francetvinfo.fr support (#2119)
+
+Nick Gal <nickgal@me.com> (1):
+      Update steam plugin to work with steam.tv urls
+
+Petar Kukolj <petarkukolj3@yahoo.com> (5):
+      plugins.cubetv: support for live streams on cubetv.sg
+      plugins.ok_live: Changed URL regex to support VoDs
+      plugins.bilibili: Fix plugin after API change
+      plugins.twitch: Add support for {title}, {author} and {category}
+      plugins.skai: Fix plugin after site update
+
+Roman <w.romankornev@gmail.com> (2):
+      [FIX] Debug log arguments string
+      [FIX] Debug log arguments cross-platform
+
+Roman Kornev <w.romankornev@gmail.com> (1):
+      [FIX] Message duplicate
+
+Sebastian Meyer <mail@bastimeyer.de> (1):
+      Reword+reformat issue templates for consistency (#1966)
+
+Stefan de Konink <stefan@konink.de> (1):
+      Update the documentation with comments for playing YouTube Live Streams (#2156)
+
+Søren Fuglede Jørgensen <s@fuglede.dk> (1):
+      Update and reactivate plugin for dr.dk
+
+Twilight0 <twilight@freemail.gr> (1):
+      plugins.ssh101: Fixed plugin (#1916)
+
+Vincent Rozenberg <vincentrozenberg@gmail.com> (1):
+      Update npo.py
+
+Vinny <vincent.aceto@gmail.com> (1):
+      docs: Added documentation for the Funimation plugin (#2091)
+
+Visatouch Deeying <xerodotc@gmail.com> (1):
+      Fix crash on missing output.record when using player-continous-http
+
+back-to <backto@protonmail.ch> (48):
+      plugins.EuropaPlusTV: Fix for "No connection adapters were found"
+      utils.args: Moved streamlink_cli utils.args into streamlink package
+      tests.plugins: Test that each plugin has a test file (#1885)
+      plugins.zattoo: session update and allow muxed hls / dash streams (#1902)
+      plugins.tv4play: Fix for updated website
+      debug: Added Session Language code as a debug message
+      tests: run Python 3.7 tests on AppVeyor and Travis-CI (#1928)
+      plugins.rtve: Fixed AttributeError 'ZTNRClient' has no 'session'
+      plugins.twitch: Fixed AttributeError and Flake8
+      plugins.filmon: Fixed AttributeError
+      plugins.crunchyroll: Fixed AttributeError and Flake8
+      tests.localization: use en_CA instead of en_US for test_equivalent
+      plugins.younow: Fix for session error and plugin cleanup
+      plugins.media_ccc_de: removed plugin
+      plugins.pixiv: use API for the stream URL and cache login cookies
+      plugins.youtube: Added support for {author} and {title} (#1944)
+      docs-CLI: Fix for sort and prog issue
+      plugins.ceskatelevize: Fix for https issues
+      plugins.mjunoon: use a User-Agent
+      api.useragents: use newer and more common User-Agent's
+      script.makeinstaller: use a more recent version of Python and Pycryptodome
+      Removed old Livestreamer deprecations and API references
+      plugins.sportal: Removed old RTMP streams, use HLS
+      plugins.twitch: new video URL regex
+      Removed old or unwanted Streamlink Plugins
+      tests: use unittest instead of pytest for itertags error (#1999)
+      utils.parse_xml: allow a tab for ignore_ns
+      plugins.afreeca: ignore new preloading urls
+      plugins.filmon: use the same cdn for a playlist url (#2074)
+      plugins.teleclubzoom: New plugin for teleclubzoom.ch
+      plugins.oldlivestream: remove plugin, service not available anymore (#2081)
+      travis: increase git clone depth
+      stream.dash_manifest: Fixed bug for dynamic playlists when parent.id is None
+      plugins.ustreamtv: use Desktop instead of Mobile streams (#2082)
+      plugins.youtube: Added support for embedded livestream urls
+      versioneer: always use 7 characters
+      plugins.stv: New Plugin for https://player.stv.tv/live
+      plugins.sbscokr: New Plugin for http://play.sbs.co.kr/onair/pc/index.html
+      plugins.vtvgo: New plugin for https://vtvgo.vn/
+      travis-ci: Fixed Python 3.8 error's
+      plugins.cdnbg: Update for extra channels (#2186)
+      api.useragents: update User-Agent list
+      plugins.afreeca: use Referer for every connection (#2204)
+      plugins.trt: Added support for https url, fixed logger error
+      plugins.turkuvaz: Added support for channel 'apara'
+      plugins.tvrby: Fixed broken plugin.
+      plugins.youtube: replace "gaming" with "www" subdomain
+      plugins.kanal7: Fixed iframe_re/stream_re, added new domain
+
+bastimeyer <mail@bastimeyer.de> (6):
+      Fix bug report template
+      Move/rename issue templates
+      Update generic issue template
+      plugins.euronews: fix live stream API URL scheme
+      Fix installer by moving additional files
+      feature: {best,worst}-unfiltered stream synonyms
+
+beardypig <beardypig@protonmail.com> (23):
+      plugins.live_russia_tv: fix for live streams, and support for VOD
+      plugin args: if args are suppressed, ignore them
+      plugin.tvtoya: refactor, add tests, plugin docs, etc.
+      stream.dash: fix bug where timeline_segments.t can be None
+      stream.hls: only include audio/video streams in MuxedHLSStreams
+      stream.hls: if the primary video stream has audio then include it
+      plugins.facebook: support for videos in posts
+      plugins.steam: api requests now require a session id
+      test for rounding dash stream bitrate
+      stream.dash: make the bitrate name for videos more human friendly
+      plugins.schoolism: add support for assignment feedback videos
+      plugins.senategov: support for hearing streams on senate.gov
+      plugins.stadium: support for live stream on watchstadium.com
+      plugins.funimationnow: workaround for #1899, see #2088
+      cli: make the HH part of HH:MM:SS options optional
+      plugins.bbciplayer: change in the mediator info in the page layout
+      plugins.btsports: fix for change in login flow
+      plugins.filmon: fix for live tv URLs that start with channel
+      plugin.powerapp: support for "tvs" URLs
+      setup: update requests to latest version and set urllib3 to match
+      CI: make sure all the dev dependencies are up to date
+      plugins.tf1: update to support new DASH streams
+      plugins.tf1: re-add support for HLS with the new API
+
+beardypig <git@beardypig.com> (7):
+      Test coverage increase (#1646)
+      Handle unicode log message in Python 2 (#1886)
+      Update method for finding YouTube videoIds (#1888)
+      stream.dash: prefer audio streams based on the user's locale (#1927)
+      plugins.openrectv: update to match site changes and title support (#1968)
+      URL builder utils (#1675)
+      cli: disable progress output for -o when no tty is available (#2090)
+
+fozzy <fozzy@fozzy.co> (1):
+      update regex to support new pattern
+
+fozzy <fozzysec@gmail.com> (1):
+      plugins.egame: new plugin for egame.qq.com (#2070)
+
+jackyzy823 <jackyzy823@gmail.com> (2):
+      Plugin Request: new plugin for Abema.tv (#1949)
+      Improve terminal progress display for  wide characters (#2032)
+
+mp107 <mp107@users.noreply.github.com> (1):
+      plugins.ltvlmslv: new Plugin for Latvian live TV channels on ltv.lsm.lv (#1986)
+
+qkolj <qkolj@users.noreply.github.com> (5):
+      plugins.tamago: support for live streams on player.tamago.live (#2108)
+      plugins.huomao: Fix plugin after website changes (#2134)
+      plugins.metube: Add support for live streams and  VoDs on www.metube.id (#2112)
+      plugins.tvibo: Add support for livestreams on player.tvibo.com (#2130)
+      Fix recording added in #920 (#2152)
+
+remek30 <remek30@users.noreply.github.com> (1):
+      plugins.toya: support for tvtoya.pl
+
+skulblakka <pascal.romahn@mailbox.org> (1):
+      [picarto.tv] Fix regarding changed URL (#1935)
+
+yoya3312 <40212627+yoya3312@users.noreply.github.com> (1):
+      plugins.youtube: use new "hlsManifestUrl" for Livestreams (#2238)
+```
+
+
 ## streamlink 0.14.2 (2018-06-28)
 
 Just a few small fixes in this release. 
diff --git a/LICENSE b/LICENSE
index 49fb9840..b38cbab5 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,5 +1,5 @@
 Copyright (c) 2011-2016, Christopher Rosell
-Copyright (c) 2016-2018, Streamlink Team
+Copyright (c) 2016-2019, Streamlink Team
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
diff --git a/docs/_themes/sphinx_rtd_theme_violet/LICENSE b/docs/_themes/sphinx_rtd_theme_violet/LICENSE
index 50dc02e6..9b33112e 100644
--- a/docs/_themes/sphinx_rtd_theme_violet/LICENSE
+++ b/docs/_themes/sphinx_rtd_theme_violet/LICENSE
@@ -2,7 +2,7 @@ The MIT License (MIT)
 
 Copyright (c) 2013 Dave Snider
 Copyright (c) 2014 Christopher Rosell
-Copyright (c) 2015-2018 Streamlink
+Copyright (c) 2015-2019 Streamlink
 
 Permission is hereby granted, free of charge, to any person obtaining a copy of
 this software and associated documentation files (the "Software"), to deal in
diff --git a/docs/conf.py b/docs/conf.py
index 9bf738c4..56c68923 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -37,7 +37,7 @@ master_doc = 'index'
 
 # General information about the project.
 project = 'Streamlink'
-copyright = '2018, Streamlink'
+copyright = '2019, Streamlink'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
diff --git a/docs/install.rst b/docs/install.rst
index bae970e4..f870358f 100644
--- a/docs/install.rst
+++ b/docs/install.rst
@@ -49,6 +49,9 @@ Distribution                         Installing
                                         $ nix-env -iA nixos.streamlink
 
                                      `NixOS channel`_
+`OpenBSD`_                           .. code-block:: console
+
+                                        $ doas pkg_add streamlink
 `Solus`_                             .. code-block:: console
 
                                         $ sudo eopkg install streamlink
@@ -70,6 +73,7 @@ Distribution                         Installing
 .. _Gentoo Linux: https://packages.gentoo.org/package/net-misc/streamlink
 .. _NetBSD (pkgsrc): http://pkgsrc.se/multimedia/streamlink
 .. _NixOS: https://github.com/NixOS/nixpkgs/tree/master/pkgs/applications/video/streamlink
+.. _OpenBSD: http://openports.se/multimedia/streamlink
 .. _Solus: https://dev.solus-project.com/source/streamlink/
 .. _Ubuntu: http://ppa.launchpad.net/nilarimogard/webupd8/ubuntu/pool/main/s/streamlink/
 .. _Void: https://github.com/void-linux/void-packages/tree/master/srcpkgs/streamlink
@@ -126,6 +130,7 @@ Fedora                               Mohamed El Morabity <melmorabity at fedorap
 Gentoo                               soredake <fdsfgs at krutt.org>
 NetBSD                               Maya Rashish <maya at netbsd.org>
 NixOS                                Tuomas Tynkkynen <tuomas.tynkkynen at iki.fi>
+OpenBSD                              Brian Callahan <bcallah at openbsd.org>
 Solus                                Bryan T. Meyers <bmeyers at datadrake.com>
 Ubuntu                               Alin Andrei <andrew at webupd8.org>
 Void                                 wkuipers <wietse at kuiprs.nl>
diff --git a/docs/plugin_matrix.rst b/docs/plugin_matrix.rst
index 79115c30..6dd3bdde 100644
--- a/docs/plugin_matrix.rst
+++ b/docs/plugin_matrix.rst
@@ -282,6 +282,7 @@ zattoo                  - zattoo.com         Yes   Yes
                         - www.quantum-tv.com
                         - www.saktv.ch
                         - www.vtxtv.ch
+                        - www.1und1.tv
 zdf_mediathek           zdf.de               Yes   Yes   Streams may be geo-restricted to Germany.
 zengatv                 zengatv.com          Yes   No
 zhanqi                  zhanqi.tv            Yes   No
diff --git a/src/streamlink/__init__.py b/src/streamlink/__init__.py
index 8cb33913..82e8f712 100644
--- a/src/streamlink/__init__.py
+++ b/src/streamlink/__init__.py
@@ -15,7 +15,7 @@ del get_versions
 __title__ = "streamlink"
 __license__ = "Simplified BSD"
 __author__ = "Streamlink"
-__copyright__ = "Copyright 2018 Streamlink"
+__copyright__ = "Copyright 2019 Streamlink"
 __credits__ = [
     "Agustín Carrasco (@asermax)",
     "Andrew Bashore (@bashtech)",
diff --git a/src/streamlink/plugins/bbciplayer.py b/src/streamlink/plugins/bbciplayer.py
index 5e5d0f28..dec5978d 100644
--- a/src/streamlink/plugins/bbciplayer.py
+++ b/src/streamlink/plugins/bbciplayer.py
@@ -187,13 +187,20 @@ class BBCiPlayer(Plugin):
         :return: Whether authentication was successful
         :rtype: bool
         """
+        def auth_check(res):
+            return ptrt_url in ([h.url for h in res.history] + [res.url])
+
+        # make the session request to get the correct cookies
         session_res = self.session.http.get(
             self.session_url,
             params=dict(ptrt=ptrt_url)
         )
 
-        http_nonce = self._extract_nonce(session_res)
+        if auth_check(session_res):
+            log.debug("Already authenticated, skipping authentication")
+            return True
 
+        http_nonce = self._extract_nonce(session_res)
         res = self.session.http.post(
             self.auth_url,
             params=dict(
@@ -208,7 +215,7 @@ class BBCiPlayer(Plugin):
             ),
             headers={"Referer": self.url})
 
-        return len(res.history) != 0
+        return auth_check(res)
 
     def _get_streams(self):
         if not self.get_option("username"):
diff --git a/src/streamlink/plugins/dogus.py b/src/streamlink/plugins/dogus.py
index e5314137..cf446fde 100644
--- a/src/streamlink/plugins/dogus.py
+++ b/src/streamlink/plugins/dogus.py
@@ -1,9 +1,14 @@
 import re
+import logging
 
 from streamlink.plugin import Plugin
+from streamlink.plugin.api.utils import itertags
+from streamlink.plugins.youtube import YouTube
 from streamlink.stream import HLSStream
 from streamlink.utils import update_scheme
 
+log = logging.getLogger(__name__)
+
 
 class Dogus(Plugin):
     """
@@ -14,13 +19,13 @@ class Dogus(Plugin):
         (?:
             ntv.com.tr/canli-yayin/ntv|
             ntvspor.net/canli-yayin|
-            kralmuzik.com.tr/tv/kral-tv|
-            kralmuzik.com.tr/tv/kral-pop-tv|
+            kralmuzik.com.tr/tv/|
             eurostartv.com.tr/canli-izle
         )/?""", re.VERBOSE)
     mobile_url_re = re.compile(r"""(?P<q>["'])(?P<url>(https?:)?//[^'"]*?/live/hls/[^'"]*?\?token=)
                                    (?P<token>[^'"]*?)(?P=q)""", re.VERBOSE)
     token_re = re.compile(r"""token=(?P<q>["'])(?P<token>[^'"]*?)(?P=q)""")
+    kral_token_url = "https://service.kralmuzik.com.tr/version/gettoken"
 
     @classmethod
     def can_handle_url(cls, url):
@@ -28,18 +33,31 @@ class Dogus(Plugin):
 
     def _get_streams(self):
         res = self.session.http.get(self.url)
-        mobile_url_m = self.mobile_url_re.search(res.text)
-
-        mobile_url = mobile_url_m and update_scheme(self.url, mobile_url_m.group("url"))
 
-        token = mobile_url_m and mobile_url_m.group("token")
-        if not token:
-            # if no token is in the url, try to find it else where in the page
-            token_m = self.token_re.search(res.text)
-            token = token_m and token_m.group("token")
+        # Look for Youtube embedded video first
+        for iframe in itertags(res.text, 'iframe'):
+            if YouTube.can_handle_url(iframe.attributes.get("src")):
+                log.debug("Handing off to YouTube plugin")
+                return self.session.streams(iframe.attributes.get("src"))
 
-        return HLSStream.parse_variant_playlist(self.session, mobile_url + token,
-                                                headers={"Referer": self.url})
+        # Next check for HLS URL with token
+        mobile_url_m = self.mobile_url_re.search(res.text)
+        mobile_url = mobile_url_m and update_scheme(self.url, mobile_url_m.group("url"))
+        if mobile_url:
+            log.debug("Found mobile stream: {0}".format(mobile_url_m.group(0)))
+
+            token = mobile_url_m and mobile_url_m.group("token")
+            if not token and "kralmuzik" in self.url:
+                log.debug("Getting Kral Muzik HLS stream token from API")
+                token = self.session.http.get(self.kral_token_url).text
+            elif not token:
+                # if no token is in the url, try to find it else where in the page
+                log.debug("Searching for HLS stream token in URL")
+                token_m = self.token_re.search(res.text)
+                token = token_m and token_m.group("token")
+
+            return HLSStream.parse_variant_playlist(self.session, mobile_url + token,
+                                                    headers={"Referer": self.url})
 
 
 __plugin__ = Dogus
diff --git a/src/streamlink/plugins/tf1.py b/src/streamlink/plugins/tf1.py
index 7c81d54f..1e4abb57 100644
--- a/src/streamlink/plugins/tf1.py
+++ b/src/streamlink/plugins/tf1.py
@@ -1,74 +1,58 @@
 from __future__ import print_function
+
+import logging
 import re
 
-from streamlink.compat import urlparse, parse_qsl
+from streamlink import PluginError
+from streamlink.compat import urljoin
 from streamlink.plugin import Plugin
 from streamlink.plugin.api import useragents
-from streamlink.stream import HDSStream
-from streamlink.stream import HLSStream
-from streamlink.utils.url import update_qsd
+from streamlink.stream import DASHStream, HLSStream
+
+log = logging.getLogger(__name__)
 
 
 class TF1(Plugin):
     url_re = re.compile(r"https?://(?:www\.)?(?:tf1\.fr/([\w-]+)/direct|(lci).fr/direct)/?")
-    embed_url = "http://www.wat.tv/embedframe/live{0}"
-    embed_re = re.compile(r"urlLive.*?:.*?\"(http.*?)\"", re.MULTILINE)
-    api_url = "http://www.wat.tv/get/{0}/591997"
-    swf_url = "http://www.wat.tv/images/v70/PlayerLite.swf"
-    hds_channel_remap = {"tf1": "androidliveconnect",
-                         "lci": "androidlivelci",
-                         "tfx": "nt1live",
-                         "hd1": "hd1live",  # renamed to tfx
-                         "tf1-series-films": "hd1live"}
-    hls_channel_remap = {"lci": "LCI",
-                         "tf1": "V4",
-                         "tfx": "nt1",
-                         "tf1-series-films": "hd1"}
+    api_url_base = "https://delivery.tf1.fr/mytf1-wrd/"
+    token = "07e45841-a17a-47cf-af64-a42311bdcc3d"
+
+    def api_call(self, channel, useragent=useragents.CHROME):
+        url = urljoin(self.api_url_base, "L_"+channel.upper())
+        req = self.session.http.get(url,
+                                    params=dict(token=self.token),
+                                    headers={"User-Agent": useragent})
+        return self.session.http.json(req)
+
+    def get_stream_urls(self, channel):
+        for useragent in [useragents.CHROME, useragents.IPHONE_6]:
+            data = self.api_call(channel, useragent)
+
+            if data.get("error"):
+                log.error("Failed to get stream for {0}: {error} ({code})".format(channel, **data))
+            else:
+                log.debug("Got {format} stream {url}".format(**data))
+                yield data['format'], data['url']
 
     @classmethod
     def can_handle_url(cls, url):
         return cls.url_re.match(url) is not None
 
-    def _get_hds_streams(self, channel):
-        channel = self.hds_channel_remap.get(channel, "{0}live".format(channel))
-        self.logger.debug("Using HDS channel name: {0}".format(channel))
-        manifest_url = self.session.http.get(self.api_url.format(channel),
-                                params={"getURL": 1},
-                                headers={"User-Agent": useragents.FIREFOX}).text
-
-        for s in HDSStream.parse_manifest(self.session,
-                                          manifest_url,
-                                          pvswf=self.swf_url,
-                                          headers={"User-Agent": useragents.FIREFOX}).items():
-            yield s
-
-    def _get_hls_streams(self, channel):
-        channel = self.hls_channel_remap.get(channel, channel)
-        embed_url = self.embed_url.format(channel)
-        self.logger.debug("Found embed URL: {0}", embed_url)
-        # page needs to have a mobile user agent
-        embed_page = self.session.http.get(embed_url, headers={"User-Agent": useragents.ANDROID})
-
-        m = self.embed_re.search(embed_page.text)
-        if m:
-            # remove all query string arguments except hdnea
-            hls_stream_url = update_qsd(m.group(1), {"hdnea": None}, remove="*")
-            try:
-                for s in HLSStream.parse_variant_playlist(self.session, hls_stream_url).items():
-                    yield s
-            except Exception:
-                self.logger.error("Failed to load the HLS playlist for {0}", channel)
-
     def _get_streams(self):
         m = self.url_re.match(self.url)
         if m:
             channel = m.group(1) or m.group(2)
             self.logger.debug("Found channel {0}", channel)
-            for s in self._get_hds_streams(channel):
-                yield s
-
-            for s in self._get_hls_streams(channel):
-                yield s
-
+            for sformat, url in self.get_stream_urls(channel):
+                try:
+                    if sformat == "dash":
+                        for s in DASHStream.parse_manifest(self.session, url, headers={"User-Agent": useragents.CHROME}).items():
+                            yield s
+                    if sformat == "hls":
+                        for s in HLSStream.parse_variant_playlist(self.session, url).items():
+                            yield s
+                except PluginError as e:
+                    log.error("Could not open {0} stream".format(sformat))
+                    log.debug("Failed with error: {0}".format(e))
 
 __plugin__ = TF1
diff --git a/src/streamlink/plugins/ustreamtv.py b/src/streamlink/plugins/ustreamtv.py
index 31fa7138..d025ef1d 100644
--- a/src/streamlink/plugins/ustreamtv.py
+++ b/src/streamlink/plugins/ustreamtv.py
@@ -83,7 +83,7 @@ class UHSClient(object):
         log.debug("Connecting to {0}".format(self.host))
         self._ws = websocket.create_connection(self.host,
                                                header=["User-Agent: {0}".format(useragents.CHROME)],
-                                               origin="http://www.ustream.tv")
+                                               origin="https://www.ustream.tv")
 
         args = dict(type="viewer",
                     appId=self._app_id,
@@ -269,9 +269,11 @@ class UHSStream(Stream):
             while not self.stopped.wait(0):
                 try:
                     cmd_args = self.api.recv()
-                except SocketError as err:
+                except (SocketError,
+                        websocket._exceptions.WebSocketConnectionClosedException) as err:
                     cmd_args = None
-                    if err.errno in (errno.ECONNRESET, errno.ETIMEDOUT):
+                    if (hasattr(err, "errno") and err.errno in (errno.ECONNRESET, errno.ETIMEDOUT)
+                            or "Connection is already closed." in str(err)):
                         while True:
                             # --stream-timeout will handle the timeout
                             try:
@@ -285,6 +287,8 @@ class UHSStream(Stream):
                                 sleep(reconnect_time_ws)
                     else:
                         raise
+                except PluginError:
+                    continue
 
                 if not cmd_args:
                     continue
@@ -390,7 +394,7 @@ class UStreamTV(Plugin):
                     res["streams"] = []
                     for stream in flv_segmented["streams"]:
                         res["streams"] += [dict(
-                            stream_name=stream["preset"],
+                            stream_name="{0}p".format(stream["videoCodec"]["height"]),
                             path=urljoin(path,
                                          stream["segmentUrl"].replace("%", "%s")),
                             hashes=flv_segmented["hashes"],
@@ -434,7 +438,6 @@ class UStreamTV(Plugin):
             api.connect()
 
             streams_data = {}
-            streams = {}
             for _ in range(5):
                 # do not use to many tries, it might take longer for a timeout
                 # when streamFormats is {} and contentAvailable is True
@@ -450,11 +453,12 @@ class UStreamTV(Plugin):
                         log.debug("Unexpected `{0}` command".format(data["cmd"]))
                         log.trace("{0!r}".format(data))
                 except ModuleInfoNoStreams:
-                    return None
+                    break
 
                 if streams_data.get("streams") and streams_data.get("cdn_url"):
-                    for s in streams_data["streams"]:
-                        streams[s["stream_name"]] = UHSStream(
+                    for s in sorted(streams_data["streams"],
+                                    key=lambda k: (k["stream_name"], k["path"])):
+                        yield s["stream_name"], UHSStream(
                             session=self.session,
                             api=api,
                             first_chunk_data=ChunkData(
@@ -465,7 +469,7 @@ class UStreamTV(Plugin):
                             template_url=urljoin(streams_data["cdn_url"],
                                                  s["path"]),
                         )
-                    return streams
+                    break
 
     def _get_media_app(self):
         umatch = self.url_re.match(self.url)
diff --git a/src/streamlink/plugins/zattoo.py b/src/streamlink/plugins/zattoo.py
index 9a8c4a01..c4f726a1 100644
--- a/src/streamlink/plugins/zattoo.py
+++ b/src/streamlink/plugins/zattoo.py
@@ -43,7 +43,7 @@ class Zattoo(Plugin):
                 tvonline\.ewe|nettv\.netcologne|tvplus\.m-net
             )\.de
             )|(?:(?:
-                player\.waly|www\.netplus
+                player\.waly|www\.(?:1und1|netplus)
             )\.tv)
             |www\.bbv-tv\.net
             |www\.meinewelt\.cc


Test patch:
diff --git a/tests/plugins/test_bbciplayer.py b/tests/plugins/test_bbciplayer.py
index cef746fe..381307de 100644
--- a/tests/plugins/test_bbciplayer.py
+++ b/tests/plugins/test_bbciplayer.py
@@ -1,5 +1,4 @@
 import json
-import logging
 import unittest
 
 from requests import Response, Request
diff --git a/tests/plugins/test_zattoo.py b/tests/plugins/test_zattoo.py
index 98fecc58..cc9360e4 100644
--- a/tests/plugins/test_zattoo.py
+++ b/tests/plugins/test_zattoo.py
@@ -21,6 +21,8 @@ class TestPluginZattoo(unittest.TestCase):
         self.assertTrue(Zattoo.can_handle_url('http://tvonline.ewe.de/watch/zdf'))
         self.assertTrue(Zattoo.can_handle_url('https://nettv.netcologne.de/watch/daserste'))
         self.assertTrue(Zattoo.can_handle_url('https://nettv.netcologne.de/watch/zdf'))
+        self.assertTrue(Zattoo.can_handle_url('https://www.1und1.tv/watch/daserste'))
+        self.assertTrue(Zattoo.can_handle_url('https://www.1und1.tv/watch/zdf'))
         # zattoo live
         self.assertTrue(Zattoo.can_handle_url('https://zattoo.com/watch/daserste'))
         self.assertTrue(Zattoo.can_handle_url('https://zattoo.com/watch/zdf'))