Index: /titan/mediathek/localhoster/lib/common.py
===================================================================
--- /titan/mediathek/localhoster/lib/common.py	(revision 42559)
+++ /titan/mediathek/localhoster/lib/common.py	(revision 42560)
@@ -17,4 +17,5 @@
 """
 import os
+from net import Net, get_ua  # @UnusedImport
 #from lib import log_utils  # @UnusedImport
 #from lib.net import Net  # @UnusedImport
@@ -34,5 +35,5 @@
 
 
-
+RAND_UA = get_ua()
 IE_USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko'
 #FF_USER_AGENT = 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Maxthon/4.4.7.3000 Chrome/30.0.1599.101 Safari/537.36'
Index: /titan/mediathek/localhoster/lib/net.py
===================================================================
--- /titan/mediathek/localhoster/lib/net.py	(revision 42559)
+++ /titan/mediathek/localhoster/lib/net.py	(revision 42560)
@@ -16,5 +16,5 @@
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 '''
-
+import random
 import cookielib
 import gzip
@@ -24,21 +24,47 @@
 import urllib2
 import socket
-from urlparse import urlparse
-from urlparse import urlunparse
 import time
-
-class HeadRequest(urllib2.Request):
-    '''A Request class that sends HEAD requests'''
-    def get_method(self):
-        return 'HEAD'
+#import kodi
+
+# Set Global timeout - Useful for slow connections and Putlocker.
+socket.setdefaulttimeout(10)
+
+BR_VERS = [
+    ['%s.0' % i for i in xrange(18, 50)],
+    ['37.0.2062.103', '37.0.2062.120', '37.0.2062.124', '38.0.2125.101', '38.0.2125.104', '38.0.2125.111', '39.0.2171.71', '39.0.2171.95', '39.0.2171.99', '40.0.2214.93', '40.0.2214.111',
+     '40.0.2214.115', '42.0.2311.90', '42.0.2311.135', '42.0.2311.152', '43.0.2357.81', '43.0.2357.124', '44.0.2403.155', '44.0.2403.157', '45.0.2454.101', '45.0.2454.85', '46.0.2490.71',
+     '46.0.2490.80', '46.0.2490.86', '47.0.2526.73', '47.0.2526.80', '48.0.2564.116', '49.0.2623.112', '50.0.2661.86'],
+    ['11.0'],
+    ['8.0', '9.0', '10.0', '10.6']]
+WIN_VERS = ['Windows NT 10.0', 'Windows NT 7.0', 'Windows NT 6.3', 'Windows NT 6.2', 'Windows NT 6.1', 'Windows NT 6.0', 'Windows NT 5.1', 'Windows NT 5.0']
+FEATURES = ['; WOW64', '; Win64; IA64', '; Win64; x64', '']
+RAND_UAS = ['Mozilla/5.0 ({win_ver}{feature}; rv:{br_ver}) Gecko/20100101 Firefox/{br_ver}',
+            'Mozilla/5.0 ({win_ver}{feature}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/{br_ver} Safari/537.36',
+            'Mozilla/5.0 ({win_ver}{feature}; Trident/7.0; rv:{br_ver}) like Gecko',
+            'Mozilla/5.0 (compatible; MSIE {br_ver}; {win_ver}{feature}; Trident/6.0)']
+def get_ua():
+#    try: last_gen = int(kodi.get_setting('last_ua_create'))
+    try: last_gen = 0
+    except: last_gen = 0
+#    if not kodi.get_setting('current_ua') or last_gen < (time.time() - (7 * 24 * 60 * 60)):
+#    if not last_gen < (time.time() - (7 * 24 * 60 * 60)):
+    index = random.randrange(len(RAND_UAS))
+    versions = {'win_ver': random.choice(WIN_VERS), 'feature': random.choice(FEATURES), 'br_ver': random.choice(BR_VERS[index])}
+    user_agent = RAND_UAS[index].format(**versions)
+        # logger.log('Creating New User Agent: %s' % (user_agent), log_utils.LOGDEBUG)
+#        kodi.set_setting('current_ua', user_agent)
+#        kodi.set_setting('last_ua_create', str(int(time.time())))
+#    else:
+#        user_agent = kodi.get_setting('current_ua')
+    return user_agent
 
 class Net:
     '''
     This class wraps :mod:`urllib2` and provides an easy way to make http
-    requests while taking care of cookies, proxies, gzip compression and 
+    requests while taking care of cookies, proxies, gzip compression and
     character encoding.
-    
+
     Example::
-    
+
         from addon.common.net import Net
         net = Net()
@@ -46,48 +72,25 @@
         print response.content
     '''
-    IE_USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko'
-    FF_USER_AGENT = 'Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.0'
-    IOS_USER_AGENT = 'Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25'
-    ANDROID_USER_AGENT = 'Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Mobile Safari/537.36'
-
-    _cj = cookielib.MozillaCookieJar()
-
+
+    _cj = cookielib.LWPCookieJar()
     _proxy = None
-    _user_agent = 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.72 Safari/537.36'
-    _accept = 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
+    _user_agent = 'Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.0'
     _http_debug = False
-    _socket_timeout = 60
-
-    def __init__(self, cookie_file='', proxy='', user_agent='', 
-                 http_debug=False, accept=_accept, socket_timeout=_socket_timeout, cloudflare=False):
+
+    def __init__(self, cookie_file='', proxy='', user_agent='', http_debug=False):
         '''
         Kwargs:
             cookie_file (str): Full path to a file to be used to load and save
             cookies to.
-            
-            proxy (str): Proxy setting (eg. 
+
+            proxy (str): Proxy setting (eg.
             ``'http://user:pass@example.com:1234'``)
-            
-            user_agent (str): String to use as the User Agent header. If not 
+
+            user_agent (str): String to use as the User Agent header. If not
             supplied the class will use a default user agent (chrome)
-            
+
             http_debug (bool): Set ``True`` to have HTTP header info written to
             the XBMC log for all requests.
-            
-            accept (str) : String to use as HTTP Request Accept header.
-            
-            socket_timeout (int): time in seconds for socket connections to wait until time out
-
-            cloudflare (bool): Set ``True`` to check all requests that raise HTTPError 503 for Cloudflare challenge and solve
-            This can be changed per request as well, see http_GET, http_PUSH
-        '''
-    
-        #Set socket timeout - Useful for slow connections
-        socket.setdefaulttimeout(socket_timeout)
-
-        # empty jar for each instance rather than scope of the import
-        self._cloudflare_jar = cookielib.MozillaCookieJar()
-
-        self.cloudflare = cloudflare
+        '''
         if cookie_file:
             self.set_cookies(cookie_file)
@@ -98,10 +101,9 @@
         self._http_debug = http_debug
         self._update_opener()
-        
-    
+
     def set_cookies(self, cookie_file):
         '''
         Set the cookie file and try to load cookies from it if it exists.
-        
+
         Args:
             cookie_file (str): Full path to a file to be used to load and save
@@ -114,25 +116,25 @@
         except:
             return False
-        
-    
-    def get_cookies(self):
+
+    def get_cookies(self, as_dict=False):
         '''Returns A dictionary containing all cookie information by domain.'''
-        return self._cj._cookies
-
+        if as_dict:
+            return dict((cookie.name, cookie.value) for cookie in self._cj)
+        else:
+            return self._cj._cookies
 
     def save_cookies(self, cookie_file):
         '''
         Saves cookies to a file.
-        
+
         Args:
             cookie_file (str): Full path to a file to save cookies to.
         '''
-        self._cj.save(cookie_file, ignore_discard=True)        
-
-        
+        self._cj.save(cookie_file, ignore_discard=True)
+
     def set_proxy(self, proxy):
         '''
         Args:
-            proxy (str): Proxy setting (eg. 
+            proxy (str): Proxy setting (eg.
             ``'http://user:pass@example.com:1234'``)
         '''
@@ -140,10 +142,8 @@
         self._update_opener()
 
-        
     def get_proxy(self):
         '''Returns string containing proxy details.'''
         return self._proxy
-        
-        
+
     def set_user_agent(self, user_agent):
         '''
@@ -153,15 +153,13 @@
         self._user_agent = user_agent
 
-        
     def get_user_agent(self):
         '''Returns user agent string.'''
         return self._user_agent
 
-
-    def _update_opener(self, cloudflare_jar=False):
-        """
+    def _update_opener(self):
+        '''
         Builds and installs a new opener to be used by all future calls to
         :func:`urllib2.urlopen`.
-        """
+        '''
         if self._http_debug:
             http = urllib2.HTTPHandler(debuglevel=1)
@@ -169,12 +167,6 @@
             http = urllib2.HTTPHandler()
 
-        if cloudflare_jar:
-            self._cloudflare_jar = cookielib.MozillaCookieJar()
-            jar = self._cloudflare_jar
-        else:
-            jar = self._cj
-
         if self._proxy:
-            opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(jar),
+            opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self._cj),
                                           urllib2.ProxyHandler({'http':
                                                                 self._proxy}),
@@ -183,390 +175,125 @@
 
         else:
-            opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(jar),
+            opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self._cj),
                                           urllib2.HTTPBasicAuthHandler(),
                                           http)
         urllib2.install_opener(opener)
 
-
-    def _parseJSString(self, s):
-        """
-        lambda
-        plugin.video.genesis\resources\lib\libraries\cloudflare.py
-        https://offshoregit.com/lambda81/
-        """
-        try:
-            offset=1 if s[0]=='+' else 0
-            val = int(eval(s.replace('!+[]','1').replace('!![]','1').replace('[]','0').replace('(','str(')[offset:]))
-            return val
-        except:
-            raise Exception
-
-
-    def _cloudflare_challenge(self, url, challenge, form_data={}, headers={}, compression=True):
-        """
-        Use _set_cloudflare to call this, not intended to be called directly.
-        Solve challenge and make request with cloudflare cookie jar
-
-        Part from:
-        lambda
-        plugin.video.genesis\resources\lib\libraries\cloudflare.py
-        https://offshoregit.com/lambda81/
-        """
-        jschl = re.compile('name="jschl_vc" value="(.+?)"/>').findall(challenge)[0]
-        init = re.compile('setTimeout\(function\(\){\s*.*?.*:(.*?)};').findall(challenge)[0]
-        builder = re.compile(r"challenge-form\'\);\s*(.*)a.v").findall(challenge)[0]
-        decrypt_val = self._parseJSString(init)
-        lines = builder.split(';')
-
-        for line in lines:
-            if len(line)>0 and '=' in line:
-                sections=line.split('=')
-                line_val = self._parseJSString(sections[1])
-                decrypt_val = int(eval(str(decrypt_val)+sections[0][-1]+str(line_val)))
-
-        path = urlparse(url).path
-        netloc = urlparse(url).netloc
-        if not netloc:
-            netloc = path
-
-        answer = decrypt_val + len(netloc)
-
-        url = url.rstrip('/')
-        query = '%s/cdn-cgi/l/chk_jschl?jschl_vc=%s&jschl_answer=%s' % (url, jschl, answer)
-
-        if 'type="hidden" name="pass"' in challenge:
-            passval = re.compile('name="pass" value="(.*?)"').findall(challenge)[0]
-            query = '%s/cdn-cgi/l/chk_jschl?pass=%s&jschl_vc=%s&jschl_answer=%s' % \
-                    (url, urllib.quote_plus(passval), jschl, answer)
-            time.sleep(9)
-
-        self._update_opener(cloudflare_jar=True)
-        req = urllib2.Request(query)
+    def http_GET(self, url, headers={}, compression=True):
+        '''
+        Perform an HTTP GET request.
+
+        Args:
+            url (str): The URL to GET.
+
+        Kwargs:
+            headers (dict): A dictionary describing any headers you would like
+            to add to the request. (eg. ``{'X-Test': 'testing'}``)
+
+            compression (bool): If ``True`` (default), try to use gzip
+            compression.
+
+        Returns:
+            An :class:`HttpResponse` object containing headers and other
+            meta-information about the page and the page content.
+        '''
+        return self._fetch(url, headers=headers, compression=compression)
+
+    def http_POST(self, url, form_data, headers={}, compression=True):
+        '''
+        Perform an HTTP POST request.
+
+        Args:
+            url (str): The URL to POST.
+
+            form_data (dict): A dictionary of form data to POST.
+
+        Kwargs:
+            headers (dict): A dictionary describing any headers you would like
+            to add to the request. (eg. ``{'X-Test': 'testing'}``)
+
+            compression (bool): If ``True`` (default), try to use gzip
+            compression.
+
+        Returns:
+            An :class:`HttpResponse` object containing headers and other
+            meta-information about the page and the page content.
+        '''
+        return self._fetch(url, form_data, headers=headers, compression=compression)
+
+    def http_HEAD(self, url, headers={}):
+        '''
+        Perform an HTTP HEAD request.
+
+        Args:
+            url (str): The URL to GET.
+
+        Kwargs:
+            headers (dict): A dictionary describing any headers you would like
+            to add to the request. (eg. ``{'X-Test': 'testing'}``)
+
+        Returns:
+            An :class:`HttpResponse` object containing headers and other
+            meta-information about the page.
+        '''
+        request = urllib2.Request(url)
+        request.get_method = lambda: 'HEAD'
+        request.add_header('User-Agent', self._user_agent)
+        for key in headers:
+            request.add_header(key, headers[key])
+        response = urllib2.urlopen(request)
+        return HttpResponse(response)
+
+    def _fetch(self, url, form_data={}, headers={}, compression=True):
+        '''
+        Perform an HTTP GET or POST request.
+
+        Args:
+            url (str): The URL to GET or POST.
+
+            form_data (dict): A dictionary of form data to POST. If empty, the
+            request will be a GET, if it contains form data it will be a POST.
+
+        Kwargs:
+            headers (dict): A dictionary describing any headers you would like
+            to add to the request. (eg. ``{'X-Test': 'testing'}``)
+
+            compression (bool): If ``True`` (default), try to use gzip
+            compression.
+
+        Returns:
+            An :class:`HttpResponse` object containing headers and other
+            meta-information about the page and the page content.
+        '''
+        req = urllib2.Request(url)
         if form_data:
-            form_data = urllib.urlencode(form_data)
-            req = urllib2.Request(query, form_data)
+            if isinstance(form_data, basestring):
+                form_data = form_data
+            else:
+                form_data = urllib.urlencode(form_data, True)
+            req = urllib2.Request(url, form_data)
         req.add_header('User-Agent', self._user_agent)
-        for k, v in headers.items():
-            req.add_header(k, v)
+        for key in headers:
+            req.add_header(key, headers[key])
         if compression:
             req.add_header('Accept-Encoding', 'gzip')
-        try:
-            response = urllib2.urlopen(req)
-        except urllib2.HTTPError as e:
-            pass
-
-
-    def _set_cloudflare(self, url, challenge, form_data={}, headers={}, compression=True):
-        """
-        Entry Point for _cloudflare_challenge
-        Calls cloudflare_challenge on netloc, not full url w/ path
-        Puts any cloudflare cookies in the main cookie jar
-        Args:
-            url (str): The URL to site of potential Cloudflare IUA.
-
-            challenge (str): html contents of the page that raised 503, containing potential Cloudflare IUA Challenge
-        Kwargs:
-            form_data (dict): A dictionary of form data if pass-through from POST.
-
-            headers (dict): A dictionary describing any headers you would like
-            to add to the request. (eg. ``{'X-Test': 'testing'}``)
-
-            compression (bool): If ``True`` (default), try to use gzip
-            compression.
-        """
-        netloc = urlparse(url).netloc
-        if not netloc:
-            netloc = urlparse(url).path
-        cloudflare_url = urlunparse((urlparse(url).scheme, netloc, '', '', '', ''))
-        try:
-            self._cloudflare_challenge(cloudflare_url, challenge, form_data, headers, compression)
-            for c in self._cloudflare_jar:
-                self._cj.set_cookie(c)
-            self._update_opener()
-        except:
-            # make sure we update to main jar
-            self._update_opener()
-            raise Exception
-
-
-    def url_with_headers(self, url, referer=None, user_agent=None, cookies=None, proxy=None, connection_timeout=None,
-                         encoding='', accept_charset='', sslcipherlist='', noshout='false', seekable='1'):
-        '''
-        Return url with Referer, User-Agent, Cookies, Proxy, Connection-Timeout, Encoding, Accept-Charset,
-        SSLCipherList, NoShout and Seekable
-        Based on: https://github.com/xbmc/xbmc/blob/master/xbmc/filesystem/CurlFile.cpp#L782
-        Args:
-            url (str): The URL to append headers to.
-
-        Kwargs:
-            referer (str): If None (default), urlunparse((urlparse(url).scheme, netloc, path, '', '', '')) is used and append if set
-
-            user_agent (str): If None (default), self._user_agent is used and append if set
-
-            cookies (bool): If ``None`` (default), use self.cloudflare as bool (False as default)
-            Append cookies to URL as well
-
-            proxy (str): If None (default), self.proxy is used and append if set
-
-            connection_timeout (str): If None (default), self._socket_timeout is used and append if set
-
-            encoding (str): append if set
-
-            accept_charset (str): append if set
-
-            sslcipherlist (str): append if set
-
-            noshout (str): 'true'/'false', skip shout, append if 'true' ('false' is kodi default)
-
-            seekable (str): '0'/'1', append if 0 ('1' is kodi default)
-        Returns:
-            http://example.com/myimage.png|Referer=%%%%%&User-Agent=%%%%%...
-        '''
-        kodi_schemes = ('special', 'plugin', 'script', 'profile')
-        if ('://' not in url) or (url.startswith(kodi_schemes)):
-            # don't waste time and return url
-            return url
-
-        _tmp = re.search('(.+?)(?:\|.*|$)', url)
-        if _tmp:
-            # trim any headers that may already be attached to url
-            url = _tmp.group(1)
-
-        if referer is not None:
-            try:
-                referer = str(referer)
-            except:
-                referer = None
-        if referer is None:
-            path = urlparse(url).path
-            netloc = urlparse(url).netloc
-            if not netloc:
-                netloc = path
-                path = ''
-            referer = urlunparse((urlparse(url).scheme, netloc, path, '', '', ''))
-            if referer == url:
-                index = path.rfind('/')
-                if index >= 0:
-                    referer = urlunparse((urlparse(url).scheme, netloc, path[:index], '', '', ''))
-        if user_agent is None:
-            user_agent = self._user_agent
-        else:
-            try:
-                user_agent = str(user_agent)
-            except:
-                user_agent = self._user_agent
-        if cookies is None:
-            cookies = self.cloudflare
-        if proxy is None:
-            proxy = self._proxy
-        if connection_timeout is None:
-            connection_timeout = self._socket_timeout
-        try:
-            connection_timeout = str(connection_timeout)
-        except:
-            connection_timeout = None
-        try:
-            if str(seekable) != '0':
-                seekable = None
-        except:
-            seekable = None
-        try:
-            if str(noshout).lower() != 'true':
-                noshout = None
-        except:
-            noshout = None
-
-        url += '|Referer=' + urllib.quote_plus(referer) + '&User-Agent=' + urllib.quote_plus(user_agent)
-        if proxy:
-            try:
-                url += '&HTTPProxy=' + urllib.quote_plus(str(proxy))
-            except:
-                pass
-        if connection_timeout:
-            url += '&Connection-Timeout=' + urllib.quote_plus(connection_timeout)
-        if encoding:
-            try:
-                url += '&Encoding=' + urllib.quote_plus(str(encoding))
-            except:
-                pass
-        if accept_charset:
-            try:
-                url += '&Accept-Charset=' + urllib.quote_plus(str(accept_charset))
-            except:
-                pass
-        if sslcipherlist:
-            try:
-                url += '&SSLCipherList=' + urllib.quote_plus(str(sslcipherlist))
-            except:
-                pass
-        if noshout:
-            url += '&NoShout=' + urllib.quote_plus(str(noshout).lower())
-        if seekable:
-            url += '&Seekable=' + urllib.quote_plus(str(seekable))
-        if cookies:
-            cookie_string = ''
-            for c in self._cj:
-                if c.domain and (c.domain.lstrip('.') in url):
-                    cookie_string += '%s=%s;' % (c.name, c.value)
-            if cookie_string:
-                url += '&Cookie=' + urllib.quote_plus(cookie_string)
-        return url
-
-
-    def http_GET(self, url, headers={}, compression=True, cloudflare=None):
-        '''
-        Perform an HTTP GET request.
-        
-        Args:
-            url (str): The URL to GET.
-            
-        Kwargs:
-            headers (dict): A dictionary describing any headers you would like
-            to add to the request. (eg. ``{'X-Test': 'testing'}``)
-
-            compression (bool): If ``True`` (default), try to use gzip 
-            compression.
-
-            cloudflare (bool): If ``None`` (default), use self.cloudflare as bool (False as default)
-            On HTTPError 503 check for Cloudflare challenge and solve
-        Returns:
-            An :class:`HttpResponse` object containing headers and other 
-            meta-information about the page and the page content.
-        '''
-        if cloudflare is None:
-            cloudflare = self.cloudflare
-        return self._fetch(url, headers=headers, compression=compression, cloudflare=cloudflare)
-        
-
-    def http_POST(self, url, form_data, headers={}, compression=True, cloudflare=None):
-        '''
-        Perform an HTTP POST request.
-        
-        Args:
-            url (str): The URL to POST.
-            
-            form_data (dict): A dictionary of form data to POST.
-            
-        Kwargs:
-            headers (dict): A dictionary describing any headers you would like
-            to add to the request. (eg. ``{'X-Test': 'testing'}``)
-
-            compression (bool): If ``True`` (default), try to use gzip 
-            compression.
-
-            cloudflare (bool): If ``None`` (default), use self.cloudflare as bool (False as default)
-            On HTTPError 503 check for Cloudflare challenge and solve
-        Returns:
-            An :class:`HttpResponse` object containing headers and other 
-            meta-information about the page and the page content.
-        '''
-        if cloudflare is None:
-            cloudflare = self.cloudflare
-        return self._fetch(url, form_data, headers=headers,
-                           compression=compression, cloudflare=cloudflare)
-
-    
-    def http_HEAD(self, url, headers={}):
-        '''
-        Perform an HTTP HEAD request.
-        
-        Args:
-            url (str): The URL to GET.
-        
-        Kwargs:
-            headers (dict): A dictionary describing any headers you would like
-            to add to the request. (eg. ``{'X-Test': 'testing'}``)
-        
-        Returns:
-            An :class:`HttpResponse` object containing headers and other 
-            meta-information about the page.
-        '''
-        req = HeadRequest(url)
-        req.add_header('User-Agent', self._user_agent)
-        req.add_header('Accept', self._accept)
-        for k, v in headers.items():
-            req.add_header(k, v)
+        req.add_unredirected_header('Host', req.get_host())
         response = urllib2.urlopen(req)
         return HttpResponse(response)
 
-
-    def _fetch(self, url, form_data={}, headers={}, compression=True, cloudflare=None):
-        '''
-        Perform an HTTP GET or POST request.
-        
-        Args:
-            url (str): The URL to GET or POST.
-            
-            form_data (dict): A dictionary of form data to POST. If empty, the 
-            request will be a GET, if it contains form data it will be a POST.
-            
-        Kwargs:
-            headers (dict): A dictionary describing any headers you would like
-            to add to the request. (eg. ``{'X-Test': 'testing'}``)
-
-            compression (bool): If ``True`` (default), try to use gzip 
-            compression.
-
-            cloudflare (bool): If ``None`` (default), use self.cloudflare as bool (False as default)
-            On HTTPError 503 check for Cloudflare challenge and solve
-        Returns:
-            An :class:`HttpResponse` object containing headers and other 
-            meta-information about the page and the page content.
-        '''
-        if cloudflare is None:
-            cloudflare = self.cloudflare
-        encoding = ''
-        req = urllib2.Request(url)
-        if form_data:
-            form_data = urllib.urlencode(form_data)
-            req = urllib2.Request(url, form_data)
-        req.add_header('User-Agent', self._user_agent)
-        for k, v in headers.items():
-            req.add_header(k, v)
-        if compression:
-            req.add_header('Accept-Encoding', 'gzip')
-        if not cloudflare:
-            response = urllib2.urlopen(req)
-            return HttpResponse(response)
-        else:
-            try:
-                response = urllib2.urlopen(req)
-                return HttpResponse(response)
-            except urllib2.HTTPError as e:
-                if e.code == 503:
-                    try:
-                        self._set_cloudflare(url, e.read(), form_data, headers, compression)
-                    except:
-                        raise urllib2.HTTPError, e
-                    req = urllib2.Request(url)
-                    if form_data:
-                        form_data = urllib.urlencode(form_data)
-                        req = urllib2.Request(url, form_data)
-                    req.add_header('User-Agent', self._user_agent)
-                    for k, v in headers.items():
-                        req.add_header(k, v)
-                    if compression:
-                        req.add_header('Accept-Encoding', 'gzip')
-                    response = urllib2.urlopen(req)
-                    return HttpResponse(response)
-                else:
-                    raise urllib2.HTTPError, e
-
-
 class HttpResponse:
     '''
-    This class represents a response from an HTTP request.
-    
+    This class represents a resoponse from an HTTP request.
+
     The content is examined and every attempt is made to properly encode it to
     Unicode.
-    
+
     .. seealso::
-        :meth:`Net.http_GET`, :meth:`Net.http_HEAD` and :meth:`Net.http_POST` 
+        :meth:`Net.http_GET`, :meth:`Net.http_HEAD` and :meth:`Net.http_POST`
     '''
-    
+
     content = ''
-    '''Unicode encoded string containing the body of the response.'''
-    
-    
+    '''Unicode encoded string containing the body of the reposne.'''
+
     def __init__(self, response):
         '''
@@ -576,13 +303,17 @@
         '''
         self._response = response
-        html = response.read()
+
+    @property
+    def content(self):
+        html = self._response.read()
+        encoding = None
         try:
-            if response.headers['content-encoding'].lower() == 'gzip':
+            if self._response.headers['content-encoding'].lower() == 'gzip':
                 html = gzip.GzipFile(fileobj=StringIO.StringIO(html)).read()
         except:
             pass
-        
+
         try:
-            content_type = response.headers['content-type']
+            content_type = self._response.headers['content-type']
             if 'charset=' in content_type:
                 encoding = content_type.split('charset=')[-1]
@@ -590,37 +321,24 @@
             pass
 
-        r = re.search('<meta\s+http-equiv="Content-Type"\s+content="(?:.+?);' +
-                      '\s+charset=(.+?)"', html, re.IGNORECASE)
+        r = re.search('<meta\s+http-equiv="Content-Type"\s+content="(?:.+?);\s+charset=(.+?)"', html, re.IGNORECASE)
         if r:
-            encoding = r.group(1) 
-                   
-        try:
-            html = unicode(html, encoding)
-        except:
-            pass
+            encoding = r.group(1)
         
-        #try:
-        #    if response.headers['content-encoding'].lower() == 'gzip':
-        #        r = re.search('<meta\s+http-equiv="Content-Type"\s+content="(?:.+?);' + '\s+charset=(.+?)"', html, re.IGNORECASE)
-        #        if r:
-        #        	encoding = r.group(1) 
-        #        	try:
-        #        		html = unicode(html, encoding)
-        #        	except:
-        #        		pass
-        #except:
-        #    pass
-            
-        self.content = html
-    
-    
-    def get_headers(self):
-        '''Returns a List of headers returned by the server.'''
-        return self._response.info().headers
-    
+        if encoding is not None:
+            try: html = html.decode(encoding)
+            except: pass
+        return html
         
+    def get_headers(self, as_dict=False):
+        '''Returns headers returned by the server.
+        If as_dict is True, headers are returned as a dictionary otherwise a list'''
+        if as_dict:
+            return dict([(item[0].title(), item[1]) for item in self._response.info().items()])
+        else:
+            return self._response.info().headers
+
     def get_url(self):
         '''
-        Return the URL of the resource retrieved, commonly used to determine if 
+        Return the URL of the resource retrieved, commonly used to determine if
         a redirect was followed.
         '''
Index: /titan/mediathek/localhoster/streamango.py
===================================================================
--- /titan/mediathek/localhoster/streamango.py	(revision 42559)
+++ /titan/mediathek/localhoster/streamango.py	(revision 42560)
@@ -45,34 +45,25 @@
     def get_media_url(self, host, media_id):
         web_url = self.get_url(host, media_id)
-
-#        headers = {'User-Agent': common.RAND_UA}
-        headers = {'User-Agent': common.FF_USER_AGENT}
-
+        headers = {'User-Agent': common.RAND_UA}
+#        headers = {'User-Agent': common.FF_USER_AGENT}
         html = self.net.http_GET(web_url, headers=headers).content
-#        print "html", html.encode('utf8')
 
         if html:
-            if re.search('>Sorry!<', html):
-                print "errormsg=Sorry!\n%s" % (str(re.compile('<p class="lead">*(.+?)</p>').findall(html)[0]))
-#                print 'errormsg=File was deleted.'
-            else:
-                encoded = re.search('''srces\.push\({type:"video/mp4",src:\w+\('([^']+)',(\d+)''', html)
-                if encoded:
-                    source = self.decode(encoded.group(1), int(encoded.group(2)))
-                    if source:
-                        source = "http:%s" % source if source.startswith("//") else source
-                        source = source.split("/")
-                        if not source[-1].isdigit():
-                          source[-1] = re.sub('[^\d]', '', source[-1])
-                        source = "/".join(source)
-                        headers.update({'Referer': web_url})
-#                        return source + helpers.append_headers(headers)
-                        print source + helpers.append_headers(headers)
-        
-#        raise ResolverError("Unable to locate video")
-                else:
-                    print 'errormsg=Unable to locate encoded video'
-        else:
-            print 'errormsg=Error 404 Website not found !'
+#           srces.push( {type:"video/mp4",src:d('keDN2p3bx6LdzqrO1JcSxaDTkZoRyuDbzaLN0KzR2qHQza7NyJ/U4N8Lld4IltoMlN3Cn98Sl90JkN=SlpHQ/K3YnqnW3uENltwA',93),height:360,bitrate:576});
+            encoded = re.search('''srces\.push\({type:"video/mp4",src:\w+\('([^']+)',(\d+)''', html)
+            if not encoded:
+                encoded = re.search('''srces\.push\( {type:"video/mp4",src:\w+\('([^']+)',(\d+)''', html)
+
+            if encoded:
+                source = self.decode(encoded.group(1), int(encoded.group(2)))
+                if source:
+                    source = "http:%s" % source if source.startswith("//") else source
+                    source = source.split("/")
+                    if not source[-1].isdigit():
+                      source[-1] = re.sub('[^\d]', '', source[-1])
+                    source = "/".join(source)
+
+                    headers.update({'Referer': web_url})
+                    print source + helpers.append_headers(headers)
 
 #<h1 style="text-align: center !important;">Sorry!</h1>
@@ -114,4 +105,6 @@
 
     def get_url(self, host, media_id):
+        if host.lower() == 'streamango.com':
+            host = 'fruitstreams.com'
         return 'http://%s/embed/%s' % (host, media_id)
 
