Browse Source

new beginning

A 4 years ago
parent
commit
2f198c161e

+ 0 - 0
Neues Textdokument.txt


+ 15 - 4
addon.xml

@@ -1,15 +1,26 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<addon id="plugin.video.cryflix_beta" name="[COLOR red]Cry[/COLOR]flix_beta" version="2.2.4">
+<addon id="plugin.video.cryflix_beta" name="[COLOR red]Plu[/COLOR]gin_beta" version="3.0.3">
     <requires>
     <requires>
-        <import addon="xbmc.python" version="2.1.0"/>
-        <import addon="script.module.simplejson" version="2.0.10"/>
-        <import addon="script.module.six" version="1.11.0"/>
         <import addon="script.module.requests" version="2.12.4"/>
         <import addon="script.module.requests" version="2.12.4"/>
+        <import addon="script.module.simplejson" optional="true"/>
+        <import addon="plugin.video.youtube" optional="true"/>
+        <import addon="inputstream.adaptive" optional="true"/>
     </requires>
     </requires>
     <extension point="xbmc.python.pluginsource" library="startup.py">
     <extension point="xbmc.python.pluginsource" library="startup.py">
         <provides>video</provides>
         <provides>video</provides>
     </extension>
     </extension>
     <extension point="xbmc.addon.metadata">
     <extension point="xbmc.addon.metadata">
         <platform>all</platform>
         <platform>all</platform>
+        <description lang="en">Version: 3.0.3
+Erstellt: 22.10.2020 - 18:17:47
+Release: beta</description>
+        <assets>
+            <icon>icon.png</icon>
+            <banner>icon.png</banner>
+            <clearlogo>icon.png</clearlogo>
+            <landscape>icon.png</landscape>
+            <thumb>icon.png</thumb>
+            <fanart>fanart.jpg</fanart>
+        </assets>
     </extension>
     </extension>
 </addon>
 </addon>

+ 13 - 4
addon_template.xml

@@ -1,15 +1,24 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<addon id="plugin.video.cryflix%RELEASE%" name="[COLOR red]Cry[/COLOR]flix%RELEASE%" version="2.2.4">
+<addon id="plugin.video.cryflix%RELEASE%" name="[COLOR red]Plu[/COLOR]gin%RELEASE%" version="%VERSION%">
     <requires>
     <requires>
-        <import addon="xbmc.python" version="2.1.0"/>
-        <import addon="script.module.simplejson" version="2.0.10"/>
-        <import addon="script.module.six" version="1.11.0"/>
         <import addon="script.module.requests" version="2.12.4"/>
         <import addon="script.module.requests" version="2.12.4"/>
+        <import addon="script.module.simplejson" optional="true"/>
+        <import addon="plugin.video.youtube" optional="true"/>
+        <import addon="inputstream.adaptive" optional="true"/>
     </requires>
     </requires>
     <extension point="xbmc.python.pluginsource" library="startup.py">
     <extension point="xbmc.python.pluginsource" library="startup.py">
         <provides>video</provides>
         <provides>video</provides>
     </extension>
     </extension>
     <extension point="xbmc.addon.metadata">
     <extension point="xbmc.addon.metadata">
         <platform>all</platform>
         <platform>all</platform>
+        <description lang="en">Version: %VERSION%%NEWLINE%Erstellt: %DATE%%NEWLINE%Release: %CHANNEL%</description>
+        <assets>
+            <icon>icon.png</icon>
+            <banner>icon.png</banner>
+            <clearlogo>icon.png</clearlogo>
+            <landscape>icon.png</landscape>
+            <thumb>icon.png</thumb>
+            <fanart>fanart.jpg</fanart>
+        </assets>
     </extension>
     </extension>
 </addon>
 </addon>

+ 20 - 10
framework/__init__.py

@@ -7,12 +7,21 @@ import xbmcplugin
 import xbmcaddon
 import xbmcaddon
 import xbmcgui
 import xbmcgui
 
 
-from common import enum
-from common import clean_dict
-from request import Request
-from listitem import ListItem
-from urls import UrlRule, NotFoundException, AmbiguousUrlException
-from storage import TimedStorage
+from .request import Request
+from .listitem import ListItem
+from .urls import UrlRule, NotFoundException, AmbiguousUrlException
+from .storage import TimedStorage
+
+if sys.version_info[0] >= 3:
+    unicode = str
+    basestring = (bytes, str)
+else:
+    long = int
+
+try:
+    from xbmcvfs import translatePath
+except ImportError:
+    from xbmc import translatePath
 
 
 
 
 class Plugin(object):
 class Plugin(object):
@@ -34,7 +43,7 @@ class Plugin(object):
         self._end_of_directory = False
         self._end_of_directory = False
         self._force_update = False
         self._force_update = False
         self._rule = None
         self._rule = None
-        self._addondata_path = xbmc.translatePath('special://profile/addon_data/%s/' % self._addon_id)
+        self._addondata_path = translatePath('special://profile/addon_data/%s/' % self._addon_id)
         self._storage_path = os.path.join(self._addondata_path, ".storage/")
         self._storage_path = os.path.join(self._addondata_path, ".storage/")
         if not os.path.isdir(self._storage_path):
         if not os.path.isdir(self._storage_path):
             os.makedirs(self._storage_path)
             os.makedirs(self._storage_path)
@@ -241,6 +250,7 @@ class Plugin(object):
                               view_mode=view_mode,
                               view_mode=view_mode,
                               goto_top=goto_top)
                               goto_top=goto_top)
             return f
             return f
+
         return decorator
         return decorator
 
 
     def add_url_rule(self, url_rule, view_func, name,
     def add_url_rule(self, url_rule, view_func, name,
@@ -329,7 +339,7 @@ class Plugin(object):
                     xbmc.sleep(self._delay - 75)
                     xbmc.sleep(self._delay - 75)
 
 
                 if self._goto_top and (not self._rule or self._rule.goto_top):
                 if self._goto_top and (not self._rule or self._rule.goto_top):
-                    xbmc.executebuiltin("XBMC.Action(firstpage)")
+                    xbmc.executebuiltin("Action(firstpage)")
 
 
                 if self._delay > 0:
                 if self._delay > 0:
                     xbmc.sleep(75)
                     xbmc.sleep(75)
@@ -390,13 +400,13 @@ class Plugin(object):
                     listitems = self.finish(listitems, cache_to_disc=rule.cache, update_listing=True if self._force_update else rule.update)
                     listitems = self.finish(listitems, cache_to_disc=rule.cache, update_listing=True if self._force_update else rule.update)
 
 
             return listitems, rule
             return listitems, rule
-        raise NotFoundException, 'No matching view found for %s' % path
+        raise NotFoundException('No matching view found for %s' % path)
 
 
     def notify(self, msg='', title=None, delay=5000, image=''):
     def notify(self, msg='', title=None, delay=5000, image=''):
         if title is None:
         if title is None:
             title = self._name
             title = self._name
 
 
-        xbmc.executebuiltin('XBMC.Notification("%s", "%s", "%s", "%s")' % (msg, title, delay, image))
+        xbmc.executebuiltin(u'Notification("%s", "%s", "%s", "%s")' % (msg, title, delay, image))
 
 
     def dialog(self, msg="", title=None):
     def dialog(self, msg="", title=None):
         if title is None:
         if title is None:

+ 11 - 7
framework/common.py

@@ -7,8 +7,15 @@
     :copyright: (c) 2012 by Jonathan Beluch
     :copyright: (c) 2012 by Jonathan Beluch
     :license: GPLv3, see LICENSE for more details.
     :license: GPLv3, see LICENSE for more details.
 '''
 '''
-import urllib
-import urllib2
+
+try:
+    import urllib.request as urllib_request  #for python 3
+    import urllib.parse as urllib_parse  #for python 3
+except ImportError:
+    import urllib2 as urllib_request  # for python 2
+    import urllib as urllib_parse
+
+
 try:
 try:
     import cPickle as pickle
     import cPickle as pickle
 except ImportError:
 except ImportError:
@@ -20,7 +27,7 @@ def xbmc_url(url, **options):
     HTTP headers to XBMC to be used when fetching a media resource, e.g.
     HTTP headers to XBMC to be used when fetching a media resource, e.g.
     cookies.
     cookies.
     '''
     '''
-    optionstring = urllib.urlencode(options)
+    optionstring = urllib_parse.urlencode(options)
     if optionstring:
     if optionstring:
         return url + '|' + optionstring
         return url + '|' + optionstring
     return url
     return url
@@ -108,10 +115,7 @@ def unpickle_dict(items):
 def download_page(url, data=None):
 def download_page(url, data=None):
     '''Returns the response for the given url. The optional data argument is
     '''Returns the response for the given url. The optional data argument is
     passed directly to urlopen.'''
     passed directly to urlopen.'''
-    conn = urllib2.urlopen(url, data)
-    resp = conn.read()
-    conn.close()
-    return resp
+    return None
 
 
 
 
 _hextochr = dict(('%02x' % i, chr(i)) for i in range(256))
 _hextochr = dict(('%02x' % i, chr(i)) for i in range(256))

+ 1 - 1
framework/listitem.py

@@ -15,7 +15,7 @@ class ListItem(object):
             'label': label,
             'label': label,
             'label2': label2,
             'label2': label2,
             'iconImage': icon,
             'iconImage': icon,
-            'thumbnailImage': thumbnail,
+            #'thumbnailImage': thumbnail,
             'path': path,
             'path': path,
         }
         }
         # kwargs = dict((key, val) for key, val in locals().items() if val is
         # kwargs = dict((key, val) for key, val in locals().items() if val is

+ 7 - 9
framework/request.py

@@ -1,13 +1,12 @@
-from common import unpickle_args
-import urlparse
+from .common import unpickle_args
+
 try:
 try:
-    from urlparse import parse_qs
+    import urllib.parse as urllib_parse  #for python 3
 except ImportError:
 except ImportError:
-    from cgi import parse_qs
+    import urlparse as urllib_parse
 
 
 
 
 class Request(object):
 class Request(object):
-
     def __init__(self, url, handle):
     def __init__(self, url, handle):
         #: The entire request url.
         #: The entire request url.
         self.url = url
         self.url = url
@@ -18,7 +17,6 @@ class Request(object):
         # urlparse doesn't like the 'plugin' scheme, so pass a protocol
         # urlparse doesn't like the 'plugin' scheme, so pass a protocol
         # relative url, e.g. //plugin.video.helloxbmc/path
         # relative url, e.g. //plugin.video.helloxbmc/path
         self.scheme, remainder = url.split(':', 1)
         self.scheme, remainder = url.split(':', 1)
-        parts = urlparse.urlparse(remainder)
-        self.netloc, self.path, self.query_string = (
-            parts[1], parts[2], parts[4])
-        self.args = unpickle_args(parse_qs(self.query_string))
+        parts = urllib_parse.urlparse(remainder)
+        self.netloc, self.path, self.query_string = (parts[1], parts[2], parts[4])
+        self.args = unpickle_args(urllib_parse.parse_qs(self.query_string))

+ 13 - 6
framework/storage.py

@@ -2,6 +2,7 @@ import os
 import csv
 import csv
 import json
 import json
 import time
 import time
+
 try:
 try:
     import cPickle as pickle
     import cPickle as pickle
 except ImportError:
 except ImportError:
@@ -14,9 +15,9 @@ from datetime import datetime
 class _PersistentDictMixin(object):
 class _PersistentDictMixin(object):
 
 
     def __init__(self, filename, flag='c', mode=None, file_format='pickle'):
     def __init__(self, filename, flag='c', mode=None, file_format='pickle'):
-        self.flag = flag                    # r=readonly, c=create, or n=new
-        self.mode = mode                    # None or an octal triple like 0644
-        self.file_format = file_format      # 'csv', 'json', or 'pickle'
+        self.flag = flag  # r=readonly, c=create, or n=new
+        self.mode = mode  # None or an octal triple like 0644
+        self.file_format = file_format  # 'csv', 'json', or 'pickle'
         self.filename = filename
         self.filename = filename
         if flag != 'n' and os.access(filename, os.R_OK):
         if flag != 'n' and os.access(filename, os.R_OK):
             fileobj = open(filename, 'rb' if file_format == 'pickle' else 'r')
             fileobj = open(filename, 'rb' if file_format == 'pickle' else 'r')
@@ -37,7 +38,15 @@ class _PersistentDictMixin(object):
             raise
             raise
         finally:
         finally:
             fileobj.close()
             fileobj.close()
-        shutil.move(tempname, self.filename)    # atomic commit
+        try:
+            os.remove(self.filename)
+        except:
+            pass
+        try:
+            shutil.copyfile(tempname, self.filename)  # atomic commit
+        except:
+            raise
+
         if self.mode is not None:
         if self.mode is not None:
             os.chmod(self.filename, self.mode)
             os.chmod(self.filename, self.mode)
 
 
@@ -80,7 +89,6 @@ class _PersistentDictMixin(object):
 
 
 
 
 class _Storage(collections.MutableMapping, _PersistentDictMixin):
 class _Storage(collections.MutableMapping, _PersistentDictMixin):
-
     '''Storage that acts like a dict but also can persist to disk.
     '''Storage that acts like a dict but also can persist to disk.
 
 
     :param filename: An absolute filepath to reprsent the storage on disk. The
     :param filename: An absolute filepath to reprsent the storage on disk. The
@@ -127,7 +135,6 @@ class _Storage(collections.MutableMapping, _PersistentDictMixin):
 
 
 
 
 class TimedStorage(_Storage):
 class TimedStorage(_Storage):
-
     '''A dict with the ability to persist to disk and TTL for items.'''
     '''A dict with the ability to persist to disk and TTL for items.'''
 
 
     def __init__(self, filename, file_format='pickle', TTL=None):
     def __init__(self, filename, file_format='pickle', TTL=None):

+ 22 - 11
framework/urls.py

@@ -1,6 +1,19 @@
+from __future__ import unicode_literals
 import re
 import re
-from urllib import urlencode, unquote_plus, quote_plus
-from common import pickle_dict, unpickle_dict
+
+try:
+    from urllib.parse import urlencode, unquote_plus, quote_plus
+except ImportError:
+    from urllib import urlencode, unquote_plus, quote_plus
+from .common import pickle_dict, unpickle_dict
+
+import sys
+
+if sys.version_info[0] >= 3:
+    unicode = str
+    long = int
+    basestring = (str, bytes)
+
 
 
 # TODO: Use regular Exceptions
 # TODO: Use regular Exceptions
 
 
@@ -14,7 +27,6 @@ class NotFoundException(Exception):
 
 
 
 
 class UrlRule(object):
 class UrlRule(object):
-
     '''This object stores the various properties related to a routing URL rule.
     '''This object stores the various properties related to a routing URL rule.
     It also provides a few methods to create URLs from the rule or to match a
     It also provides a few methods to create URLs from the rule or to match a
     given URL against a rule.
     given URL against a rule.
@@ -59,15 +71,15 @@ class UrlRule(object):
 
 
         try:
         try:
             self._regex = re.compile('^' + p + '$')
             self._regex = re.compile('^' + p + '$')
-        except re.error, e:
-            raise ValueError, ('There was a problem creating this URL rule. '
-                               'Ensure you do not have any unpaired angle '
-                               'brackets: "<" or ">"')
+        except re.error as e:
+            raise ValueError('There was a problem creating this URL rule. '
+                             'Ensure you do not have any unpaired angle '
+                             'brackets: "<" or ">"')
 
 
     def __eq__(self, other):
     def __eq__(self, other):
         return (
         return (
-            (self._name, self._url_rule, self._view_func, self._options) ==
-            (other._name, other._url_rule, other._view_func, other._options)
+                (self._name, self._url_rule, self._view_func, self._options) ==
+                (other._name, other._url_rule, other._view_func, other._options)
         )
         )
 
 
     def __ne__(self, other):
     def __ne__(self, other):
@@ -105,8 +117,7 @@ class UrlRule(object):
         '''
         '''
         for key, val in items.items():
         for key, val in items.items():
             if not isinstance(val, basestring):
             if not isinstance(val, basestring):
-                raise content_typeError, ('Value "%s" for key "%s" must be an instance'
-                                          ' of basestring' % (val, key))
+                raise Exception('Value "%s" for key "%s" must be an instance of basestring but is %s' % (val, key, str(type(val))))
             items[key] = quote_plus(val)
             items[key] = quote_plus(val)
 
 
         try:
         try:

BIN
icon_beta.png


+ 14 - 0
languageconvert.py

@@ -0,0 +1,14 @@
+import re
+
+if __name__ == "__main__":
+    content = ""
+    with open("resources/language/english/strings.xml", "r") as f:
+        content = f.read()
+
+    strings = open("resources/language/english/strings.po", "w")
+    strings.write("msgid \"\"\nmsgstr \"\"\n\n")
+
+    for matchNum, match in enumerate(re.finditer(r'<string id="([^"]+)">(.+?)<\/string>', content, re.IGNORECASE), start=1):
+        strings.write("# %s\nmsgctxt \"#%s\"\nmsgid \"%s\"\nmsgstr \"\"\n\n" % (match.group(2), match.group(1), match.group(2)))
+
+    strings.close()

+ 29 - 20
make.bat

@@ -6,39 +6,48 @@ del "output/startup.py" >NUL 2>NUL
 echo do copy...
 echo do copy...
 cd "src"
 cd "src"
 rem copy /b /Y playerwatcher.py+viewids.py+consts.py+compressedcookielib.py+utils.py+portal.py+api.py+plugin.py "..\out.py" >NUL 2>NUL
 rem copy /b /Y playerwatcher.py+viewids.py+consts.py+compressedcookielib.py+utils.py+portal.py+api.py+plugin.py "..\out.py" >NUL 2>NUL
-copy /b /Y viewids.py+watchdog.py+utils.py+consts.py+compressedcookielib.py+utils.py+api.py+plugin.py "..\out.py" >NUL 2>NUL
+copy /b /Y viewids.py+utils.py+consts.py+playserver.py+api.py+plugin.py "..\out.py" >NUL 2>NUL
 cd "..\"
 cd "..\"
-copy /b /Y utf8.txt+out.py "tmp.py"
-copy /b /Y tmp.py "out.py"
 timeout /t 1 >NUL 2>NUL
 timeout /t 1 >NUL 2>NUL
 echo do replace...
 echo do replace...
 python "replace.py" "out.py" "stable"
 python "replace.py" "out.py" "stable"
 echo do minify...
 echo do minify...
-copy /Y "out.py" "output/plugin.py" >NUL 2>NUL
-copy /Y "startup.py" "output/startup.py" >NUL 2>NUL
-rem D:\dev\Python27\Scripts\pyminifier --obfuscate-variables --obfuscate-classes --obfuscate-import-methods --prepend=utf8.txt -o "output/plugin_pure.py" out.py
+copy /Y /b out.py "tmp.py" >NUL 2>NUL
+copy /Y /b "startup.py" "output/startup.py" >NUL 2>NUL
+python pypreprocessor.py "tmp.py"
+python languageconvert.py
+copy /b /Y "tmp_out.py" "out.py"
+copy /b /Y "out.py" "tmp.py"
+C:\Python27\Scripts\pyminifier --obfuscate-variables --obfuscate-classes --obfuscate-functions --gzip_modified --prepend=utf8.txt -o tmp.py out.py
+rem C:\Python27\Scripts\pyminifier --obfuscate-variables --obfuscate-classes --obfuscate-functions --prepend=utf8_stable.txt -o tmp.py out.py
+rem C:\Python27\Scripts\pyminifier --obfuscate-variables --obfuscate-classes --obfuscate-functions --prepend=utf8_stable.txt -o tmp.py out.py
 rem D:\dev\Python27\Scripts\pyminifier --obfuscate-variables --obfuscate-classes --obfuscate-import-methods --gzip_modified --prepend=utf8.txt -o "output/plugin.py" out.py
 rem D:\dev\Python27\Scripts\pyminifier --obfuscate-variables --obfuscate-classes --obfuscate-import-methods --gzip_modified --prepend=utf8.txt -o "output/plugin.py" out.py
-rem copy /b /Y "utf8.txt"+"src\startup.py" "output\startup.py" >NUL 2>NUL
 rem D:\dev\Python27\Scripts\pyminifier --obfuscate-variables --obfuscate-classes --obfuscate-import-methods --gzip_modified --prepend=utf8.txt -o "output/startup.py" "src/startup.py"
 rem D:\dev\Python27\Scripts\pyminifier --obfuscate-variables --obfuscate-classes --obfuscate-import-methods --gzip_modified --prepend=utf8.txt -o "output/startup.py" "src/startup.py"
+copy /b /Y "tmp.py" "output/plugin.py"
 echo do cleanup...
 echo do cleanup...
 
 
 DEL /Q /F /S "*.pyc" >NUL 2>NUL
 DEL /Q /F /S "*.pyc" >NUL 2>NUL
+del tmp.py >NUL 2>NUL
 del out.py >NUL 2>NUL
 del out.py >NUL 2>NUL
 
 
-rd /s /q "../Repo/source/stable/resources" >NUL 2>NUL
-rd /s /q "../Repo/source/stable/framework" >NUL 2>NUL
+rd /s /q "C:\Users\SevenX\Dropbox\Crynet\Repo/source/stable/resources" >NUL 2>NUL
+rd /s /q "C:\Users\SevenX\Dropbox\Crynet\Repo/source/stable/framework" >NUL 2>NUL
 
 
-echo V | xcopy "resources" /f /y /s "../Repo/source/stable/resources" >NUL 2>NUL
-echo V | xcopy "framework" /f /y /s "..//Repo/source/stable/framework" >NUL 2>NUL
-echo D | xcopy "output/startup.py" /f /y "../Repo/source/stable/startup.py" >NUL 2>NUL
-echo D | xcopy "output/plugin.py" /f /y "../Repo/source/stable/plugin.py" >NUL 2>NUL
-echo D | xcopy "addon.xml" /f /y "../Repo/source/stable/addon.xml" >NUL 2>NUL
-echo D | xcopy "fanart.jpg" /f /y "../Repo/source/stable/fanart.jpg" >NUL 2>NUL
-echo D | xcopy "icon.png" /f /y "../Repo/source/stable/icon.png" >NUL 2>NUL
-echo D | xcopy "changelog.txt" /f /y "../Repo/source/stable/changelog.txt" >NUL 2>NUL
+md "resources/language/resource.language.en_us" >NUL 2>NUL
+echo V | xcopy "resources/language/english/strings.po" /f /y /s "resources/language/resource.language.en_us" >NUL 2>NUL
+echo V | xcopy "resources/language/resource.language.en_us" /f /y /s "resources/language/resource.language.en_gb" >NUL 2>NUL
 
 
+echo V | xcopy "resources" /f /y /s "C:\Users\SevenX\Dropbox\Crynet\Repo/source/stable/resources" >NUL 2>NUL
+echo V | xcopy "framework" /f /y /s "C:\Users\SevenX\Dropbox\Crynet\Repo/source/stable/framework" >NUL 2>NUL
+echo D | xcopy "output/startup.py" /f /y "C:\Users\SevenX\Dropbox\Crynet\Repo/source/stable/startup.py" >NUL 2>NUL
+echo D | xcopy "output/plugin.py" /f /y "C:\Users\SevenX\Dropbox\Crynet\Repo/source/stable/plugin.py" >NUL 2>NUL
+echo D | xcopy "addon.xml" /f /y "C:\Users\SevenX\Dropbox\Crynet\Repo/source/stable/addon.xml" >NUL 2>NUL
+echo D | xcopy "fanart.jpg" /f /y "C:\Users\SevenX\Dropbox\Crynet\Repo/source/stable/fanart.jpg" >NUL 2>NUL
+echo D | xcopy "icon.png" /f /y "C:\Users\SevenX\Dropbox\Crynet\Repo/source/stable/icon.png" >NUL 2>NUL
+echo D | xcopy "changelog.txt" /f /y "C:\Users\SevenX\Dropbox\Crynet\Repo/source/stable/changelog.txt" >NUL 2>NUL
+
+echo V | xcopy "resources" /f /y /s "C:\Users\SevenX\AppData\Roaming\Kodi\addons\plugin.video.cryflix/resources" >NUL 2>NUL
 echo D | xcopy "addon.xml" /f /y "C:\Users\SevenX\AppData\Roaming\Kodi\addons\plugin.video.cryflix/addon.xml" >NUL 2>NUL
 echo D | xcopy "addon.xml" /f /y "C:\Users\SevenX\AppData\Roaming\Kodi\addons\plugin.video.cryflix/addon.xml" >NUL 2>NUL
 echo D | xcopy "output/plugin.py" /f /y "C:\Users\SevenX\AppData\Roaming\Kodi\addons\plugin.video.cryflix/plugin.py" >NUL 2>NUL
 echo D | xcopy "output/plugin.py" /f /y "C:\Users\SevenX\AppData\Roaming\Kodi\addons\plugin.video.cryflix/plugin.py" >NUL 2>NUL
-echo D | xcopy "output/startup.py" /f /y "DC:\Users\SevenX\AppData\Roaming\Kodi\addons\plugin.video.cryflix/startup.py" >NUL 2>NUL
-
-rem pause
+echo D | xcopy "output/startup.py" /f /y "C:\Users\SevenX\AppData\Roaming\Kodi\addons\plugin.video.cryflix/startup.py" >NUL 2>NUL
+echo D | xcopy "resources/settings.xml" /f /y "C:\Users\SevenX\AppData\Roaming\Kodi\addons\plugin.video.cryflix/resources/settings.xml" >NUL 2>NUL

+ 0 - 42
make.sh

@@ -1,42 +0,0 @@
-#!/bin/sh
-mkdir -p output 2>&1 1>/dev/null
-rm -f out.py 2>&1 1>/dev/null
-rm -f "output/plugin.py" 2>&1 1>/dev/null
-rm -f "output/startup.py" 2>&1 1>/dev/null
-echo "do copy..."
-cd src
-cat uuid.py playerwatcher2.py viewids.py consts.py compressedcookielib.py utils.py portal.py api.py plugin.py >> "../out.py"
-cd ../
-echo "do replace..."
-#./replace 2>&1 > /dev/null
-python "replace.py" "out.py"
-echo "do minify..."
-cp -f "out.py" "output/plugin.py"
-cp -f "src/startup.py" "output/startup.py"
-cat utf8.txt "out.py" > "output/plugin.py"
-#/usr/local/bin/pyminifier --obfuscate-variables --obfuscate-classes --obfuscate-functions --prepend=utf8.txt -o "output/plugin_pure.py" "out.py" 2>&1 >/dev/null
-#/usr/local/bin/pyminifier --obfuscate-variables --obfuscate-classes --obfuscate-functions --prepend=utf8.txt -o "output/plugin.py" "out.py" 2>&1 >/dev/null
-#/usr/local/bin/pyminifier --obfuscate-variables --obfuscate-classes --obfuscate-functions --gzip_modified --prepend=utf8.txt -o "output/plugin.py" "out.py" 2>&1 >/dev/null
-cat utf8.txt "src/startup.py" > "output/startup.py"
-#/usr/local/bin/pyminifier --obfuscate-variables --obfuscate-classes --obfuscate-import-methods --gzip_modified --prepend=utf8.txt -o "output/startup.py" "src/startup.py" 2>&1 >/dev/null
-echo "do cleanup..."
-rm -f out.py
-
-rm -rf "../Repo/Source/resources"
-rm -rf "../Repo/Source/framework"
-rm -rf "../Repo/Source/mechanize"
-
-cp -fr "resources" "../Repo/Source/resources"
-cp -fr "framework" "../Repo/Source/framework"
-cp -fr "mechanize" "../Repo/Source/mechanize"
-cp -f "output/startup.py" "../Repo/Source/startup.py"
-cp -f "output/plugin.py" "../Repo/Source/plugin.py"
-cp -f "addon.xml" "../Repo/Source/addon.xml"
-cp -f "fanart.jpg" "../Repo/Source/fanart.jpg" 2>&1 1>/dev/null
-cp -f "icon.png" "../Repo/Source/icon.png" 2>&1 1>/dev/null 2>&1 1>/dev/null
-cp -f "changelog.txt" "../Repo/Source/changelog.txt" 2>&1 1>/dev/null
-
-cp -fR "resources" "/Users/benjamin/Library/Application Support/Kodi/addons/plugin.video.cryflix/"
-cp -f "addon.xml" "/Users/benjamin/Library/Application Support/Kodi/addons/plugin.video.cryflix/addon.xml"
-cp -f "output/plugin.py" "/Users/benjamin/Library/Application Support/Kodi/addons/plugin.video.cryflix/plugin.py"
-cp -f "output/startup.py" "/Users/benjamin/Library/Application Support/Kodi/addons/plugin.video.cryflix/startup.py"

+ 10 - 3
make_beta.bat

@@ -6,7 +6,7 @@ del "output/startup.py" >NUL 2>NUL
 echo do copy...
 echo do copy...
 cd "src"
 cd "src"
 rem copy /b /Y playerwatcher.py+viewids.py+consts.py+compressedcookielib.py+utils.py+portal.py+api.py+plugin.py "..\out.py" >NUL 2>NUL
 rem copy /b /Y playerwatcher.py+viewids.py+consts.py+compressedcookielib.py+utils.py+portal.py+api.py+plugin.py "..\out.py" >NUL 2>NUL
-copy /b /Y viewids.py+utils.py+consts.py+playserver.py+compressedcookielib.py+api.py+plugin.py "..\out.py" >NUL 2>NUL
+copy /b /Y viewids.py+utils.py+consts.py+playserver.py+api.py+plugin.py "..\out.py" >NUL 2>NUL
 cd "..\"
 cd "..\"
 timeout /t 1 >NUL 2>NUL
 timeout /t 1 >NUL 2>NUL
 echo do replace...
 echo do replace...
@@ -14,7 +14,8 @@ python "replace.py" "out.py" "beta"
 echo do minify...
 echo do minify...
 copy /Y /b out.py "tmp.py" >NUL 2>NUL
 copy /Y /b out.py "tmp.py" >NUL 2>NUL
 copy /Y /b "startup.py" "output/startup.py" >NUL 2>NUL
 copy /Y /b "startup.py" "output/startup.py" >NUL 2>NUL
-python pypreprocessor.py "tmp.py"
+C:\Python27\python pypreprocessor.py "tmp.py"
+C:\Python27\python languageconvert.py
 copy /b /Y "utf8_beta.txt"+"tmp_out.py" "out.py"
 copy /b /Y "utf8_beta.txt"+"tmp_out.py" "out.py"
 copy /b /Y "out.py" "tmp.py"
 copy /b /Y "out.py" "tmp.py"
 C:\Python27\Scripts\pyminifier --obfuscate-variables --obfuscate-classes --obfuscate-functions --gzip_modified --prepend=utf8_beta.txt -o tmp.py out.py
 C:\Python27\Scripts\pyminifier --obfuscate-variables --obfuscate-classes --obfuscate-functions --gzip_modified --prepend=utf8_beta.txt -o tmp.py out.py
@@ -32,18 +33,24 @@ del out.py >NUL 2>NUL
 rd /s /q "C:\Users\SevenX\Dropbox\Crynet\Repo/source/beta/resources" >NUL 2>NUL
 rd /s /q "C:\Users\SevenX\Dropbox\Crynet\Repo/source/beta/resources" >NUL 2>NUL
 rd /s /q "C:\Users\SevenX\Dropbox\Crynet\Repo/source/beta/framework" >NUL 2>NUL
 rd /s /q "C:\Users\SevenX\Dropbox\Crynet\Repo/source/beta/framework" >NUL 2>NUL
 
 
+md "resources/language/resource.language.en_us" >NUL 2>NUL
+echo V | xcopy "resources/language/english/strings.po" /f /y /s "resources/language/resource.language.en_us" >NUL 2>NUL
+echo V | xcopy "resources/language/resource.language.en_us" /f /y /s "resources/language/resource.language.en_gb" >NUL 2>NUL
+
 echo V | xcopy "resources" /f /y /s "C:\Users\SevenX\Dropbox\Crynet\Repo/source/beta/resources" >NUL 2>NUL
 echo V | xcopy "resources" /f /y /s "C:\Users\SevenX\Dropbox\Crynet\Repo/source/beta/resources" >NUL 2>NUL
 echo V | xcopy "framework" /f /y /s "C:\Users\SevenX\Dropbox\Crynet\Repo/source/beta/framework" >NUL 2>NUL
 echo V | xcopy "framework" /f /y /s "C:\Users\SevenX\Dropbox\Crynet\Repo/source/beta/framework" >NUL 2>NUL
 echo D | xcopy "output/startup.py" /f /y "C:\Users\SevenX\Dropbox\Crynet\Repo/source/beta/startup.py" >NUL 2>NUL
 echo D | xcopy "output/startup.py" /f /y "C:\Users\SevenX\Dropbox\Crynet\Repo/source/beta/startup.py" >NUL 2>NUL
 echo D | xcopy "output/plugin.py" /f /y "C:\Users\SevenX\Dropbox\Crynet\Repo/source/beta/plugin.py" >NUL 2>NUL
 echo D | xcopy "output/plugin.py" /f /y "C:\Users\SevenX\Dropbox\Crynet\Repo/source/beta/plugin.py" >NUL 2>NUL
 echo D | xcopy "addon.xml" /f /y "C:\Users\SevenX\Dropbox\Crynet\Repo/source/beta/addon.xml" >NUL 2>NUL
 echo D | xcopy "addon.xml" /f /y "C:\Users\SevenX\Dropbox\Crynet\Repo/source/beta/addon.xml" >NUL 2>NUL
 echo D | xcopy "fanart.jpg" /f /y "C:\Users\SevenX\Dropbox\Crynet\Repo/source/beta/fanart.jpg" >NUL 2>NUL
 echo D | xcopy "fanart.jpg" /f /y "C:\Users\SevenX\Dropbox\Crynet\Repo/source/beta/fanart.jpg" >NUL 2>NUL
-echo D | xcopy "icon.png" /f /y "C:\Users\SevenX\Dropbox\Crynet\Repo/source/beta/icon.png" >NUL 2>NUL
+echo D | xcopy "icon_beta.png" /f /y "C:\Users\SevenX\Dropbox\Crynet\Repo/source/beta/icon.png" >NUL 2>NUL
 echo D | xcopy "changelog.txt" /f /y "C:\Users\SevenX\Dropbox\Crynet\Repo/source/beta/changelog.txt" >NUL 2>NUL
 echo D | xcopy "changelog.txt" /f /y "C:\Users\SevenX\Dropbox\Crynet\Repo/source/beta/changelog.txt" >NUL 2>NUL
 
 
+echo V | xcopy "resources" /f /y /s "C:\Users\SevenX\AppData\Roaming\Kodi\addons\plugin.video.cryflix_beta/resources" >NUL 2>NUL
 echo D | xcopy "addon.xml" /f /y "C:\Users\SevenX\AppData\Roaming\Kodi\addons\plugin.video.cryflix_beta/addon.xml" >NUL 2>NUL
 echo D | xcopy "addon.xml" /f /y "C:\Users\SevenX\AppData\Roaming\Kodi\addons\plugin.video.cryflix_beta/addon.xml" >NUL 2>NUL
 echo D | xcopy "output/plugin.py" /f /y "C:\Users\SevenX\AppData\Roaming\Kodi\addons\plugin.video.cryflix_beta/plugin.py" >NUL 2>NUL
 echo D | xcopy "output/plugin.py" /f /y "C:\Users\SevenX\AppData\Roaming\Kodi\addons\plugin.video.cryflix_beta/plugin.py" >NUL 2>NUL
 echo D | xcopy "output/startup.py" /f /y "C:\Users\SevenX\AppData\Roaming\Kodi\addons\plugin.video.cryflix_beta/startup.py" >NUL 2>NUL
 echo D | xcopy "output/startup.py" /f /y "C:\Users\SevenX\AppData\Roaming\Kodi\addons\plugin.video.cryflix_beta/startup.py" >NUL 2>NUL
 echo D | xcopy "resources/settings.xml" /f /y "C:\Users\SevenX\AppData\Roaming\Kodi\addons\plugin.video.cryflix_beta/resources/settings.xml" >NUL 2>NUL
 echo D | xcopy "resources/settings.xml" /f /y "C:\Users\SevenX\AppData\Roaming\Kodi\addons\plugin.video.cryflix_beta/resources/settings.xml" >NUL 2>NUL
+echo D | xcopy "icon_beta.png" /f /y "C:\Users\SevenX\AppData\Roaming\Kodi\addons\plugin.video.cryflix_beta/icon.png" >NUL 2>NUL
 
 
 rem pause
 rem pause

+ 44 - 0
make_old.bat

@@ -0,0 +1,44 @@
+@echo off
+md output >NUL 2>NUL
+del out.py >NUL 2>NUL
+del "output/plugin.py" >NUL 2>NUL
+del "output/startup.py" >NUL 2>NUL
+echo do copy...
+cd "src"
+rem copy /b /Y playerwatcher.py+viewids.py+consts.py+compressedcookielib.py+utils.py+portal.py+api.py+plugin.py "..\out.py" >NUL 2>NUL
+copy /b /Y viewids.py+watchdog.py+utils.py+consts.py+compressedcookielib.py+utils.py+api.py+plugin.py "..\out.py" >NUL 2>NUL
+cd "..\"
+copy /b /Y utf8.txt+out.py "tmp.py"
+copy /b /Y tmp.py "out.py"
+timeout /t 1 >NUL 2>NUL
+echo do replace...
+python "replace.py" "out.py" "stable"
+echo do minify...
+copy /Y "out.py" "output/plugin.py" >NUL 2>NUL
+copy /Y "startup.py" "output/startup.py" >NUL 2>NUL
+rem D:\dev\Python27\Scripts\pyminifier --obfuscate-variables --obfuscate-classes --obfuscate-import-methods --prepend=utf8.txt -o "output/plugin_pure.py" out.py
+rem D:\dev\Python27\Scripts\pyminifier --obfuscate-variables --obfuscate-classes --obfuscate-import-methods --gzip_modified --prepend=utf8.txt -o "output/plugin.py" out.py
+rem copy /b /Y "utf8.txt"+"src\startup.py" "output\startup.py" >NUL 2>NUL
+rem D:\dev\Python27\Scripts\pyminifier --obfuscate-variables --obfuscate-classes --obfuscate-import-methods --gzip_modified --prepend=utf8.txt -o "output/startup.py" "src/startup.py"
+echo do cleanup...
+
+DEL /Q /F /S "*.pyc" >NUL 2>NUL
+del out.py >NUL 2>NUL
+
+rd /s /q "../Repo/source/stable/resources" >NUL 2>NUL
+rd /s /q "../Repo/source/stable/framework" >NUL 2>NUL
+
+echo V | xcopy "resources" /f /y /s "../Repo/source/stable/resources" >NUL 2>NUL
+echo V | xcopy "framework" /f /y /s "..//Repo/source/stable/framework" >NUL 2>NUL
+echo D | xcopy "output/startup.py" /f /y "../Repo/source/stable/startup.py" >NUL 2>NUL
+echo D | xcopy "output/plugin.py" /f /y "../Repo/source/stable/plugin.py" >NUL 2>NUL
+echo D | xcopy "addon.xml" /f /y "../Repo/source/stable/addon.xml" >NUL 2>NUL
+echo D | xcopy "fanart.jpg" /f /y "../Repo/source/stable/fanart.jpg" >NUL 2>NUL
+echo D | xcopy "icon.png" /f /y "../Repo/source/stable/icon.png" >NUL 2>NUL
+echo D | xcopy "changelog.txt" /f /y "../Repo/source/stable/changelog.txt" >NUL 2>NUL
+
+echo D | xcopy "addon.xml" /f /y "C:\Users\SevenX\AppData\Roaming\Kodi\addons\plugin.video.cryflix/addon.xml" >NUL 2>NUL
+echo D | xcopy "output/plugin.py" /f /y "C:\Users\SevenX\AppData\Roaming\Kodi\addons\plugin.video.cryflix/plugin.py" >NUL 2>NUL
+echo D | xcopy "output/startup.py" /f /y "DC:\Users\SevenX\AppData\Roaming\Kodi\addons\plugin.video.cryflix/startup.py" >NUL 2>NUL
+
+rem pause

+ 12 - 0
pyminifier-script.py

@@ -0,0 +1,12 @@
+#!C:\Python27\python.exe
+# EASY-INSTALL-ENTRY-SCRIPT: 'pyminifier==2.5','console_scripts','pyminifier'
+__requires__ = 'pyminifier==2.5'
+import re
+import sys
+from pkg_resources import load_entry_point
+
+if __name__ == '__main__':
+    sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
+    sys.exit(
+        load_entry_point('pyminifier==2.5', 'console_scripts', 'pyminifier')()
+    )

+ 27 - 2
replace.py

@@ -1,17 +1,37 @@
 import sys
 import sys
 from pprint import pprint
 from pprint import pprint
 import re
 import re
+import datetime
+
+VERSION_PATTERN = re.compile(r'^PLUGIN_VERSION\s+=\s+"([^"]+)"$', re.MULTILINE)
 
 
 if __name__ == "__main__":
 if __name__ == "__main__":
     channel = sys.argv[2] if len(sys.argv) == 3 else "stable"
     channel = sys.argv[2] if len(sys.argv) == 3 else "stable"
 
 
+    now = datetime.datetime.now()
+    date = now.strftime("%d.%m.%Y - %H:%M:%S")
+
     # Addon
     # Addon
+    with open("src/consts.py", "r") as f:
+        version_match = VERSION_PATTERN.search(f.read())
+        if version_match:
+            VERSION = version_match.group(1)
+        else:
+            VERSION = "0.0.0"
+
     content = ""
     content = ""
     with open("addon_template.xml", "r") as f:
     with open("addon_template.xml", "r") as f:
         content = f.read()
         content = f.read()
 
 
     with open("addon.xml", "w") as f:
     with open("addon.xml", "w") as f:
-        f.write(content.replace("%RELEASE%", "" if channel == "stable" else "_beta"))
+        f.write(
+            content
+                .replace("%RELEASE%", "" if channel == "stable" else "_beta")
+                .replace("%CHANNEL%", channel)
+                .replace("%NEWLINE%", "\n")
+                .replace("%VERSION%", VERSION)
+                .replace("%DATE%", date)
+        )
 
 
     # Settings
     # Settings
     content = ""
     content = ""
@@ -19,7 +39,12 @@ if __name__ == "__main__":
         content = f.read()
         content = f.read()
 
 
     with open("resources/settings.xml", "w") as f:
     with open("resources/settings.xml", "w") as f:
-        f.write(content.replace("%RELEASE%", "" if channel == "stable" else "_beta"))
+        f.write(content
+                .replace("%RELEASE%", "" if channel == "stable" else "_beta")
+                .replace("%CHANNEL%", channel)
+                .replace("%NEWLINE%", "\n")
+                .replace("%VERSION%", VERSION)
+                .replace("%DATE%", date))
 
 
     content = ""
     content = ""
     with open(sys.argv[1], "r") as f:
     with open(sys.argv[1], "r") as f:

+ 78 - 0
resources/language/english/strings.po

@@ -0,0 +1,78 @@
+msgid ""
+msgstr ""
+
+# Liste
+msgctxt "#32001"
+msgid "Liste"
+msgstr ""
+
+# Thumbnail
+msgctxt "#32002"
+msgid "Thumbnail"
+msgstr ""
+
+# Informationen
+msgctxt "#32003"
+msgid "Informationen"
+msgstr ""
+
+# Manuell
+msgctxt "#32004"
+msgid "Manuell"
+msgstr ""
+
+# Eingetragen
+msgctxt "#32005"
+msgid "Eingetragen"
+msgstr ""
+
+# Jahr
+msgctxt "#32006"
+msgid "Jahr"
+msgstr ""
+
+# IMDB Wertung
+msgctxt "#32007"
+msgid "IMDB Wertung"
+msgstr ""
+
+# Länge
+msgctxt "#32008"
+msgid "Länge"
+msgstr ""
+
+# Abwärts
+msgctxt "#32009"
+msgid "Abwärts"
+msgstr ""
+
+# Aufwärts
+msgctxt "#32010"
+msgid "Aufwärts"
+msgstr ""
+
+# 1
+msgctxt "#32018"
+msgid "1"
+msgstr ""
+
+# 2
+msgctxt "#32019"
+msgid "2"
+msgstr ""
+
+# 3
+msgctxt "#32020"
+msgid "3"
+msgstr ""
+
+# 4
+msgctxt "#32021"
+msgid "4"
+msgstr ""
+
+# 5
+msgctxt "#32022"
+msgid "5"
+msgstr ""
+

+ 0 - 8
resources/language/english/strings.xml

@@ -13,14 +13,6 @@
 	<string id="32009">Abwärts</string>
 	<string id="32009">Abwärts</string>
 	<string id="32010">Aufwärts</string>
 	<string id="32010">Aufwärts</string>
 
 
-	<string id="32011">Alle</string>
-	<string id="32012">HD &amp; Serien</string>
-	<string id="32013">HD &amp; 3D</string>
-	<string id="32014">Serien &amp; 3D</string>
-	<string id="32015">Nur HD</string>
-	<string id="32016">Nur Serien</string>
-	<string id="32017">Nur 3D</string>
-
 	<string id="32018">1</string>
 	<string id="32018">1</string>
 	<string id="32019">2</string>
 	<string id="32019">2</string>
 	<string id="32020">3</string>
 	<string id="32020">3</string>

+ 78 - 0
resources/language/resource.language.en_gb/strings.po

@@ -0,0 +1,78 @@
+msgid ""
+msgstr ""
+
+# Liste
+msgctxt "#32001"
+msgid "Liste"
+msgstr ""
+
+# Thumbnail
+msgctxt "#32002"
+msgid "Thumbnail"
+msgstr ""
+
+# Informationen
+msgctxt "#32003"
+msgid "Informationen"
+msgstr ""
+
+# Manuell
+msgctxt "#32004"
+msgid "Manuell"
+msgstr ""
+
+# Eingetragen
+msgctxt "#32005"
+msgid "Eingetragen"
+msgstr ""
+
+# Jahr
+msgctxt "#32006"
+msgid "Jahr"
+msgstr ""
+
+# IMDB Wertung
+msgctxt "#32007"
+msgid "IMDB Wertung"
+msgstr ""
+
+# Länge
+msgctxt "#32008"
+msgid "Länge"
+msgstr ""
+
+# Abwärts
+msgctxt "#32009"
+msgid "Abwärts"
+msgstr ""
+
+# Aufwärts
+msgctxt "#32010"
+msgid "Aufwärts"
+msgstr ""
+
+# 1
+msgctxt "#32018"
+msgid "1"
+msgstr ""
+
+# 2
+msgctxt "#32019"
+msgid "2"
+msgstr ""
+
+# 3
+msgctxt "#32020"
+msgid "3"
+msgstr ""
+
+# 4
+msgctxt "#32021"
+msgid "4"
+msgstr ""
+
+# 5
+msgctxt "#32022"
+msgid "5"
+msgstr ""
+

+ 78 - 0
resources/language/resource.language.en_us/strings.po

@@ -0,0 +1,78 @@
+msgid ""
+msgstr ""
+
+# Liste
+msgctxt "#32001"
+msgid "Liste"
+msgstr ""
+
+# Thumbnail
+msgctxt "#32002"
+msgid "Thumbnail"
+msgstr ""
+
+# Informationen
+msgctxt "#32003"
+msgid "Informationen"
+msgstr ""
+
+# Manuell
+msgctxt "#32004"
+msgid "Manuell"
+msgstr ""
+
+# Eingetragen
+msgctxt "#32005"
+msgid "Eingetragen"
+msgstr ""
+
+# Jahr
+msgctxt "#32006"
+msgid "Jahr"
+msgstr ""
+
+# IMDB Wertung
+msgctxt "#32007"
+msgid "IMDB Wertung"
+msgstr ""
+
+# Länge
+msgctxt "#32008"
+msgid "Länge"
+msgstr ""
+
+# Abwärts
+msgctxt "#32009"
+msgid "Abwärts"
+msgstr ""
+
+# Aufwärts
+msgctxt "#32010"
+msgid "Aufwärts"
+msgstr ""
+
+# 1
+msgctxt "#32018"
+msgid "1"
+msgstr ""
+
+# 2
+msgctxt "#32019"
+msgid "2"
+msgstr ""
+
+# 3
+msgctxt "#32020"
+msgid "3"
+msgstr ""
+
+# 4
+msgctxt "#32021"
+msgid "4"
+msgstr ""
+
+# 5
+msgctxt "#32022"
+msgid "5"
+msgstr ""
+

+ 13 - 13
resources/settings.xml

@@ -11,20 +11,20 @@
         <setting id="deviceidentifier" label="Gerätekennung ([B]mind. 2 Zeichen[/B])" type="text"/>
         <setting id="deviceidentifier" label="Gerätekennung ([B]mind. 2 Zeichen[/B])" type="text"/>
 
 
         <setting label=" " type="lsep"/>
         <setting label=" " type="lsep"/>
-        <setting label="Verbliebene Laufzeit" type="action" action='RunPlugin("plugin://plugin.video.cryflix_beta/account_status/")' visible="false"/>
+        <setting label="Verbliebene Laufzeit" type="action" action='RunPlugin("plugin://plugin.video.cryflix_beta/account_status/")' />
     </category>
     </category>
     <category label="Plugin">
     <category label="Plugin">
-        <setting id="viewlist" default="0" type="select" label="Listen View" lvalues="32001|32002|32003|32004" value="0|1|2|3"/>
-        <setting id="viewlist_man" type="number" label="Listen View ID" default="57" visible="eq(-1,Manuell)" subsetting="true"/>
+        <setting id="viewlist" default="0" type="select" label="Listen View" lvalues="32002|32002|32003|32004" value="0|1|2|3"/>
+        <setting id="viewlist_man" type="number" label="Listen View ID" default="57" subsetting="true"/>
 
 
         <setting id="viewthumbnail" default="1" type="select" label="Filme View" lvalues="32001|32002|32003|32004" value="0|1|2|3"/>
         <setting id="viewthumbnail" default="1" type="select" label="Filme View" lvalues="32001|32002|32003|32004" value="0|1|2|3"/>
-        <setting id="viewthumbnail_man" type="number" label="Filme View ID" default="500" visible="eq(-1,Manuell)" subsetting="true"/>
+        <setting id="viewthumbnail_man" type="number" label="Filme View ID" default="500" subsetting="true"/>
 
 
         <setting id="viewepisode" default="2" type="select" label="Episoden View" lvalues="32001|32002|32003|32004" value="0|1|2|3"/>
         <setting id="viewepisode" default="2" type="select" label="Episoden View" lvalues="32001|32002|32003|32004" value="0|1|2|3"/>
-        <setting id="viewepisode_man" type="number" label="Episoden View ID" default="503" visible="eq(-1,Manuell)" subsetting="true"/>
+        <setting id="viewepisode_man" type="number" label="Episoden View ID" default="503" subsetting="true"/>
 
 
         <setting id="viewwatchlist" default="1" type="select" label="Watchlist View" lvalues="32001|32002|32003|32004" value="0|1|2|3"/>
         <setting id="viewwatchlist" default="1" type="select" label="Watchlist View" lvalues="32001|32002|32003|32004" value="0|1|2|3"/>
-        <setting id="viewwatchlist_man" type="number" label="Watchlist View ID" default="500" visible="eq(-1,Manuell)" subsetting="true"/>
+        <setting id="viewwatchlist_man" type="number" label="Watchlist View ID" default="500" subsetting="true"/>
 
 
         <setting label=" " type="lsep"/>
         <setting label=" " type="lsep"/>
         <setting id="orderby_field" default="0" type="select" label="Sortierung" lvalues="32005|32006|32007|32008" value="0|1|2|3"/>
         <setting id="orderby_field" default="0" type="select" label="Sortierung" lvalues="32005|32006|32007|32008" value="0|1|2|3"/>
@@ -36,7 +36,7 @@
         <setting id="watchedlistid" default="0" type="select" label="Watchedlist Nummer" lvalues="32018|32019|32020|32021" value="0|1|2|3" visible="false"/>
         <setting id="watchedlistid" default="0" type="select" label="Watchedlist Nummer" lvalues="32018|32019|32020|32021" value="0|1|2|3" visible="false"/>
 
 
         <setting label=" " type="lsep"/>
         <setting label=" " type="lsep"/>
-        <setting id="shownewcomer" type="bool" label="Menüpunkt '[B]Neueinsteiger[/B]' anzeigen" default="false"/>
+        <setting id="shownewcomer" type="bool" label="Menüpunkt '[B]Neueinsteiger[/B]' anzeigen" default="true"/>
         <setting id="moviesperpage" type="number" label="Filme pro Seite ([B]1-150[/B])" default="50"/>
         <setting id="moviesperpage" type="number" label="Filme pro Seite ([B]1-150[/B])" default="50"/>
         <setting id="usetagline" type="bool" label="Tagline für Informationen nutzen" default="true"/>
         <setting id="usetagline" type="bool" label="Tagline für Informationen nutzen" default="true"/>
         <setting id="switchtagline" type="bool" label="Titel und Tagline vertauschen" default="false"/>
         <setting id="switchtagline" type="bool" label="Titel und Tagline vertauschen" default="false"/>
@@ -44,9 +44,8 @@
         <setting label=" " type="lsep"/>
         <setting label=" " type="lsep"/>
         <setting id="colorline" type="text" label="Farbe für Cinelines" default="red"/>
         <setting id="colorline" type="text" label="Farbe für Cinelines" default="red"/>
         <setting id="coloruhd" type="text" label="Farbe für UHD" default="yellow"/>
         <setting id="coloruhd" type="text" label="Farbe für UHD" default="yellow"/>
-        <setting id="askbeforeplay" type="bool" label="Fragen ob der Film gestartet werden soll" default="true"/>
+        <setting id="askbeforeplay" type="bool" label="Fragen ob der Film gestartet werden soll" default="false"/>
         <setting id="askfornextepisode" type="bool" label="Fragen ob die nächste Episode gestartet werden soll" default="true"/>
         <setting id="askfornextepisode" type="bool" label="Fragen ob die nächste Episode gestartet werden soll" default="true"/>
-        <setting id="viewtypes" default="0" type="select" label="Einträge Filtern nach" lvalues="32011|32012|32013|32014|32015|32016|32017" value="0|1|2|3|4|5|6"/>
     </category>
     </category>
     <!--
     <!--
     <category label="Jugendschutz">
     <category label="Jugendschutz">
@@ -75,10 +74,11 @@
 
 
         <setting label=" " type="lsep" visible="eq(-3,true)"/>
         <setting label=" " type="lsep" visible="eq(-3,true)"/>
         <setting label="Storage leeren" type="action" action='RunPlugin("plugin://plugin.video.cryflix_beta/clear_storage/")' visible="eq(-4,true)"/>
         <setting label="Storage leeren" type="action" action='RunPlugin("plugin://plugin.video.cryflix_beta/clear_storage/")' visible="eq(-4,true)"/>
+        <setting label="Playserver beenden" type="action" action='RunPlugin("plugin://plugin.video.cryflix_beta/stop_playserver/")' visible="eq(-5,true)"/>
 
 
-        <setting label=" " type="lsep" visible="eq(-5,true)"/>
-        <setting id="usesimplejson" type="bool" label="SimpleJSON anstelle von JSON nutzen" default="false" visible="eq(-6,true)"/>
-        <setting id="gototop" type="bool" label="Automatisch an den Anfang springen" default="false" visible="eq(-7,true)"/>
-        <setting id="directorydelay" type="number" label="Verzögerung Aufbau ([B]Millisekunden[/B])" default="350" visible="eq(-8,true)"/>
+        <setting label=" " type="lsep" visible="eq(-6,true)"/>
+        <setting id="usesimplejson" type="bool" label="SimpleJSON anstelle von JSON nutzen" default="false" visible="eq(-7,true)"/>
+        <setting id="gototop" type="bool" label="Automatisch an den Anfang springen" default="false" visible="eq(-8,true)"/>
+        <setting id="directorydelay" type="number" label="Verzögerung Aufbau ([B]Millisekunden[/B])" default="350" visible="eq(-9,true)"/>
     </category>
     </category>
 </settings>
 </settings>

+ 6 - 7
settings_template.xml

@@ -11,20 +11,20 @@
         <setting id="deviceidentifier" label="Gerätekennung ([B]mind. 2 Zeichen[/B])" type="text"/>
         <setting id="deviceidentifier" label="Gerätekennung ([B]mind. 2 Zeichen[/B])" type="text"/>
 
 
         <setting label=" " type="lsep"/>
         <setting label=" " type="lsep"/>
-        <setting label="Verbliebene Laufzeit" type="action" action='RunPlugin("plugin://plugin.video.cryflix%RELEASE%/account_status/")' visible="false"/>
+        <setting label="Verbliebene Laufzeit" type="action" action='RunPlugin("plugin://plugin.video.cryflix%RELEASE%/account_status/")' />
     </category>
     </category>
     <category label="Plugin">
     <category label="Plugin">
-        <setting id="viewlist" default="0" type="select" label="Listen View" lvalues="32001|32002|32003|32004" value="0|1|2|3"/>
-        <setting id="viewlist_man" type="number" label="Listen View ID" default="57" visible="eq(-1,Manuell)" subsetting="true"/>
+        <setting id="viewlist" default="0" type="select" label="Listen View" lvalues="32002|32002|32003|32004" value="0|1|2|3"/>
+        <setting id="viewlist_man" type="number" label="Listen View ID" default="57" subsetting="true"/>
 
 
         <setting id="viewthumbnail" default="1" type="select" label="Filme View" lvalues="32001|32002|32003|32004" value="0|1|2|3"/>
         <setting id="viewthumbnail" default="1" type="select" label="Filme View" lvalues="32001|32002|32003|32004" value="0|1|2|3"/>
-        <setting id="viewthumbnail_man" type="number" label="Filme View ID" default="500" visible="eq(-1,Manuell)" subsetting="true"/>
+        <setting id="viewthumbnail_man" type="number" label="Filme View ID" default="500" subsetting="true"/>
 
 
         <setting id="viewepisode" default="2" type="select" label="Episoden View" lvalues="32001|32002|32003|32004" value="0|1|2|3"/>
         <setting id="viewepisode" default="2" type="select" label="Episoden View" lvalues="32001|32002|32003|32004" value="0|1|2|3"/>
-        <setting id="viewepisode_man" type="number" label="Episoden View ID" default="503" visible="eq(-1,Manuell)" subsetting="true"/>
+        <setting id="viewepisode_man" type="number" label="Episoden View ID" default="503" subsetting="true"/>
 
 
         <setting id="viewwatchlist" default="1" type="select" label="Watchlist View" lvalues="32001|32002|32003|32004" value="0|1|2|3"/>
         <setting id="viewwatchlist" default="1" type="select" label="Watchlist View" lvalues="32001|32002|32003|32004" value="0|1|2|3"/>
-        <setting id="viewwatchlist_man" type="number" label="Watchlist View ID" default="500" visible="eq(-1,Manuell)" subsetting="true"/>
+        <setting id="viewwatchlist_man" type="number" label="Watchlist View ID" default="500" subsetting="true"/>
 
 
         <setting label=" " type="lsep"/>
         <setting label=" " type="lsep"/>
         <setting id="orderby_field" default="0" type="select" label="Sortierung" lvalues="32005|32006|32007|32008" value="0|1|2|3"/>
         <setting id="orderby_field" default="0" type="select" label="Sortierung" lvalues="32005|32006|32007|32008" value="0|1|2|3"/>
@@ -46,7 +46,6 @@
         <setting id="coloruhd" type="text" label="Farbe für UHD" default="yellow"/>
         <setting id="coloruhd" type="text" label="Farbe für UHD" default="yellow"/>
         <setting id="askbeforeplay" type="bool" label="Fragen ob der Film gestartet werden soll" default="false"/>
         <setting id="askbeforeplay" type="bool" label="Fragen ob der Film gestartet werden soll" default="false"/>
         <setting id="askfornextepisode" type="bool" label="Fragen ob die nächste Episode gestartet werden soll" default="true"/>
         <setting id="askfornextepisode" type="bool" label="Fragen ob die nächste Episode gestartet werden soll" default="true"/>
-        <setting id="viewtypes" default="0" type="select" label="Einträge Filtern nach" lvalues="32011|32012|32013|32014|32015|32016|32017" value="0|1|2|3|4|5|6"/>
     </category>
     </category>
     <!--
     <!--
     <category label="Jugendschutz">
     <category label="Jugendschutz">

+ 24 - 11
src/api.py

@@ -3,7 +3,6 @@
 
 
 from consts import *
 from consts import *
 from utils import *
 from utils import *
-import pprint
 
 
 
 
 class __api__(object):
 class __api__(object):
@@ -17,14 +16,14 @@ class __api__(object):
 
 
             elif __json__["errno"] in (-1, -2, -3, -8):
             elif __json__["errno"] in (-1, -2, -3, -8):
                 hide_busy_dialog()
                 hide_busy_dialog()
-                PLUGIN.notify(u"Version [B]%s[/B] ist nicht gültig!" % PLUGIN_VERSION)
-                output("[API] Version not valid")
+                output("[API] Version not valid, err code %s" % __json__["errno"])
                 clear_session()
                 clear_session()
 
 
-                xbmc.executebuiltin('Dialog.Close(busydialog)')
-                xbmc.executebuiltin('XBMC.Container.Update("library://video/addons.xml/",replace)')
-                xbmc.executebuiltin("XBMC.ActivateWindow(Home)")
-                sys.exit(-1)
+                hide_busy_dialog()
+                xbmc.executebuiltin('Container.Update("library://video/addons.xml/",replace)')
+                #xbmc.executebuiltin("ActivateWindow(Home)")
+                PLUGIN.dialog(u"Leider ist die Version [B]%s[/B] ist nicht gültig!" % PLUGIN_VERSION)
+                sys.exit(1)
                 return False
                 return False
 
 
             else:
             else:
@@ -53,7 +52,7 @@ class __api__(object):
 
 
         try:
         try:
             response = request.__execute__()
             response = request.__execute__()
-        except urllib2.HTTPError as e:
+        except urllib_request.HTTPError as e:
             response = e.read()
             response = e.read()
         except Exception as e:
         except Exception as e:
             output("[API] Login Error: %s " % repr(e))
             output("[API] Login Error: %s " % repr(e))
@@ -67,18 +66,21 @@ class __api__(object):
         try:
         try:
             json = string_to_json(response)
             json = string_to_json(response)
         except Exception as e:
         except Exception as e:
-            output("[API] Error: %s "% repr(e))
+            output("[API] Error: %s " % repr(e))
             return False
             return False
 
 
         if json["error"]:
         if json["error"]:
+            xbmc.log("GOT ERROR! %s" % str(json))
             if not __api__.__check_hash__(json) and __auto_login__:
             if not __api__.__check_hash__(json) and __auto_login__:
                 return __api__.__login__(False)
                 return __api__.__login__(False)
 
 
             output("[API] Error: %s" % json["error"])
             output("[API] Error: %s" % json["error"])
             return False
             return False
 
 
+        #ifdef DEBUG
         if DEBUG:
         if DEBUG:
             PLUGIN.notify("Erneut eingelogt...")
             PLUGIN.notify("Erneut eingelogt...")
+        #endif
 
 
         PORTAL_USERID = int(json["data"]["userid"])
         PORTAL_USERID = int(json["data"]["userid"])
         PORTAL_SESSION = json["data"]["sessionhash"]
         PORTAL_SESSION = json["data"]["sessionhash"]
@@ -96,6 +98,9 @@ class __api__(object):
         @param __first__:
         @param __first__:
         @return:
         @return:
         """
         """
+        global PORTAL_USERID, PORTAL_SESSION
+
+        PORTAL_USERID, PORTAL_SESSION = load_session()
 
 
         if __data__ is None:
         if __data__ is None:
             __data__ = {}
             __data__ = {}
@@ -105,12 +110,15 @@ class __api__(object):
                 return False
                 return False
 
 
         output("[API] UserID: %s" % PORTAL_USERID)
         output("[API] UserID: %s" % PORTAL_USERID)
+        #ifdef DEBUG
+        output("[API] Session: %s" % PORTAL_SESSION)
+        #endif
 
 
         request = __ApiRequest__(__endpoint__, __data__=__data__)
         request = __ApiRequest__(__endpoint__, __data__=__data__)
         response = None
         response = None
         try:
         try:
             response = request.__execute__()
             response = request.__execute__()
-        except urllib2.HTTPError as e:
+        except urllib_request.HTTPError as e:
             response = e.read()
             response = e.read()
         except:
         except:
             return False
             return False
@@ -118,7 +126,12 @@ class __api__(object):
         if not response:
         if not response:
             return False
             return False
 
 
-        json = string_to_json(response)
+        json = None
+        try:
+            json = string_to_json(response)
+        except Exception as e:
+            output("[API] Error: %s " % repr(e))
+            return False
 
 
         if json["error"]:
         if json["error"]:
             if not __api__.__check_hash__(json) and __first__:
             if not __api__.__check_hash__(json) and __first__:

+ 103 - 73
src/consts.py

@@ -1,23 +1,33 @@
 # -*- coding: utf-8 -*-
 # -*- coding: utf-8 -*-
 
 
+PLUGIN_VERSION = "3.0.3"
+PLUGIN_TOKEN = "71ab1d4f65676994fbfb45a880311bbb"
 
 
 ##define DEBUG
 ##define DEBUG
 ##define DEBUG_SERVER
 ##define DEBUG_SERVER
-
-import framework
+import random
 import xbmc
 import xbmc
-import cookielib
-import os
+import traceback
+import framework
 import xbmcgui
 import xbmcgui
-import urllib2
-import platform, sys
-import random
 import time
 import time
-import traceback
+from viewids import *
+from utils import *
+
 #ifdef DEBUG_SERVER
 #ifdef DEBUG_SERVER
 import socket
 import socket
+
 #endif
 #endif
-from utils import *
+
+try:
+    #for python 3
+    import urllib.request as urllib_request
+    import urllib.parse as urllib_parse
+    from urllib.request import pathname2url
+except ImportError:
+    import urllib2 as urllib_request  # for python 2
+    import urllib as urllib_parse
+    from urllib import pathname2url
 
 
 #ifdef DEBUG
 #ifdef DEBUG
 DEBUG = True
 DEBUG = True
@@ -25,11 +35,10 @@ DEBUG = True
 DEBUG = False
 DEBUG = False
 #endif
 #endif
 BASEPATH = "vnext.to"
 BASEPATH = "vnext.to"
-APPTITLE = "Cryflix"
+APPTITLE = "Plugin"
 DELETE_PASSWORD = False
 DELETE_PASSWORD = False
-
-CJ = cookielib.LWPCookieJar()
-
+KODI_VERSION = int(xbmc.getInfoLabel("System.BuildVersion").split(".")[0])
+xbmc.log("[KODI_VERSION] %s" % str(KODI_VERSION))
 MASTERLOCK = False, None
 MASTERLOCK = False, None
 
 
 #ifdef DEBUG_SERVER
 #ifdef DEBUG_SERVER
@@ -42,13 +51,14 @@ def output(message, to_log_file=True):
     """
     """
 
 
     @param message:
     @param message:
+    @param to_log_file:
     """
     """
 
 
     #ifdef DEBUG_SERVER
     #ifdef DEBUG_SERVER
     global sock
     global sock
     try:
     try:
         if not sock:
         if not sock:
-            sock = socket.create_connection(("192.168.1.116", 12345), timeout=1)
+            sock = socket.create_connection(("192.168.1.170", 12345), timeout=1)
 
 
         if sock:
         if sock:
             sock.send("%s\n" % message)
             sock.send("%s\n" % message)
@@ -115,7 +125,7 @@ PORTAL_SESSION = ""
 API_URL = ""
 API_URL = ""
 PORTAL_URL = ""
 PORTAL_URL = ""
 
 
-IMAGEPATH = "http://image.tmdb.org/t/p/"
+IMAGEPATH = "https://image.tmdb.org/t/p/"
 IMAGESIZE_COVER = "w185"
 IMAGESIZE_COVER = "w185"
 IMAGESIZE_SCENE = "w500"
 IMAGESIZE_SCENE = "w500"
 IMAGESIZE_POSTER = "w1280"
 IMAGESIZE_POSTER = "w1280"
@@ -127,8 +137,6 @@ if win.getWidth() >= 1600:
     # IMAGESIZE_POSTER = "original"
     # IMAGESIZE_POSTER = "original"
 
 
 PLUGIN_NAME = "kodi"
 PLUGIN_NAME = "kodi"
-PLUGIN_VERSION = PLUGIN.info("version")
-PLUGIN_TOKEN = "19d718fa70115439b9a1d994e300c1f0"
 PLUGIN_HASH = md5_string("%s%s%s" % (PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_TOKEN))
 PLUGIN_HASH = md5_string("%s%s%s" % (PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_TOKEN))
 
 
 DEVICE_IDENTIFER = ""
 DEVICE_IDENTIFER = ""
@@ -150,7 +158,7 @@ SWITCH_TAGLINE = True
 HIDE_SETTINGS = True
 HIDE_SETTINGS = True
 HIDE_LOGOUT = True
 HIDE_LOGOUT = True
 ASK_FOR_NEXT_EPISODE = True
 ASK_FOR_NEXT_EPISODE = True
-VIEW_TYPES = ""
+VIEW_TYPES = "0"
 
 
 COLOR_LINE = "red"
 COLOR_LINE = "red"
 COLOR_UHD = "yellow"
 COLOR_UHD = "yellow"
@@ -159,7 +167,11 @@ SOCKET_TIMEOUT = 10
 
 
 USER_AGENT = ""
 USER_AGENT = ""
 MOVIES_PER_PAGE = 50
 MOVIES_PER_PAGE = 50
-YOUTUBE_SEARCH_URL = "https://www.googleapis.com/youtube/v3/search?key=AIzaSyDA0A-a085kg2wB7b-0F2XLOLCpypZYYgg&part=snippet&order=relevance&q=%s&regionCode=de&type=video&relevanceLanguage=de&maxResults=50&safeSearch=none"
+YOUTUBE_KEYS = [
+    #"AIzaSyAl1Xq9DwdE_KD4AtPaE4EJl3WZe2zCqg4",
+    "AIzaSyDA0A-a085kg2wB7b-0F2XLOLCpypZYYgg"
+]
+YOUTUBE_SEARCH_URL = "https://www.googleapis.com/youtube/v3/search?key=%s&part=snippet&order=relevance&q=%s&regionCode=de&type=video&relevanceLanguage=de&maxResults=50&safeSearch=none"
 
 
 API_HEADERS = [
 API_HEADERS = [
     ("Authorization", "Bearer %s" % PLUGIN_TOKEN),
     ("Authorization", "Bearer %s" % PLUGIN_TOKEN),
@@ -182,15 +194,15 @@ def load_session():
 def clear_session():
 def clear_session():
     global PORTAL_USERID, PORTAL_SESSION
     global PORTAL_USERID, PORTAL_SESSION
 
 
-    internal_storage = PLUGIN.get_storage("session")
-    if not ("user_id" in internal_storage):
+    session_storage = PLUGIN.get_storage("session")
+    if not ("user_id" in session_storage):
         return None, None
         return None, None
 
 
     output("[SESSION] Clearing!!!!!")
     output("[SESSION] Clearing!!!!!")
 
 
-    del internal_storage["user_id"]
-    del internal_storage["session_hash"]
-    internal_storage.sync()
+    del session_storage["user_id"]
+    del session_storage["session_hash"]
+    session_storage.sync()
 
 
     PORTAL_USERID = 0
     PORTAL_USERID = 0
     PORTAL_SESSION = None
     PORTAL_SESSION = None
@@ -231,8 +243,6 @@ def read_settings():
         PORTAL_URL = "http://%s" % PORTAL_URL
         PORTAL_URL = "http://%s" % PORTAL_URL
 
 
     DEVICE_IDENTIFER = PLUGIN.get_setting("deviceidentifier")
     DEVICE_IDENTIFER = PLUGIN.get_setting("deviceidentifier")
-    if not DEVICE_IDENTIFER:
-        DEVICE_IDENTIFER = "Unknown"
 
 
     WATCHLIST_ID = PLUGIN.get_setting("watchlistid")
     WATCHLIST_ID = PLUGIN.get_setting("watchlistid")
     WATCHEDLIST_ID = PLUGIN.get_setting("watchedlistid")
     WATCHEDLIST_ID = PLUGIN.get_setting("watchedlistid")
@@ -255,19 +265,24 @@ def read_settings():
     HIDE_SETTINGS = PLUGIN.get_setting("hidesettings") == "true"
     HIDE_SETTINGS = PLUGIN.get_setting("hidesettings") == "true"
     HIDE_LOGOUT = PLUGIN.get_setting("hidelogout") == "true"
     HIDE_LOGOUT = PLUGIN.get_setting("hidelogout") == "true"
     ASK_FOR_NEXT_EPISODE = PLUGIN.get_setting("askfornextepisode") == "true"
     ASK_FOR_NEXT_EPISODE = PLUGIN.get_setting("askfornextepisode") == "true"
-    VIEW_TYPES = PLUGIN.get_setting("viewtypes")
-    if VIEW_TYPES == "1":
-        VIEW_TYPES = "1,2"
-    elif VIEW_TYPES == "2":
-        VIEW_TYPES = "1,3"
-    elif VIEW_TYPES == "3":
-        VIEW_TYPES = "2,3"
-    elif VIEW_TYPES == "4":
-        VIEW_TYPES = "1"
-    elif VIEW_TYPES == "5":
-        VIEW_TYPES = "2"
-    elif VIEW_TYPES == "6":
-        VIEW_TYPES = "3"
+
+    tmp = []
+    if not HIDE_UHD:
+        tmp.append("4")
+        tmp.append("5")
+    if not HIDE_HD:
+        tmp.append("1")
+    if not HIDE_SERIES:
+        tmp.append("2")
+    if not HIDE_3D:
+        tmp.append("3")
+
+    if not len(tmp):
+        VIEW_TYPES = "0"
+    else:
+        VIEW_TYPES = ",".join(tmp)
+
+    output("[VIEW_TYPES] %s" % VIEW_TYPES)
 
 
     MOVIES_PER_PAGE = PLUGIN.get_setting("moviesperpage")
     MOVIES_PER_PAGE = PLUGIN.get_setting("moviesperpage")
     COLOR_LINE = PLUGIN.get_setting("colorline").replace("#", "")
     COLOR_LINE = PLUGIN.get_setting("colorline").replace("#", "")
@@ -318,8 +333,10 @@ def ping():
         internal_storage["ping"] = time.time()
         internal_storage["ping"] = time.time()
         internal_storage.sync()
         internal_storage.sync()
 
 
+    #ifdef DEBUG
     if DEBUG:
     if DEBUG:
         PLUGIN.notify("Erneut gepingt...")
         PLUGIN.notify("Erneut gepingt...")
+    #endif
 
 
     return pinged
     return pinged
 
 
@@ -327,6 +344,8 @@ def ping():
 def save_session(user_id, session_hash):
 def save_session(user_id, session_hash):
     internal_storage = get_storage("session")
     internal_storage = get_storage("session")
 
 
+    xbmc.log("storage: %s" % str(internal_storage))
+
     internal_storage["user_id"] = user_id
     internal_storage["user_id"] = user_id
     internal_storage["session_hash"] = session_hash
     internal_storage["session_hash"] = session_hash
     internal_storage.sync()
     internal_storage.sync()
@@ -341,21 +360,29 @@ def save_session(user_id, session_hash):
 def save_watchtime(episode_id, time=0, seen=False):
 def save_watchtime(episode_id, time=0, seen=False):
     episode_id = str(episode_id)
     episode_id = str(episode_id)
 
 
+    internal_storage = get_storage("watched")
     if seen:
     if seen:
-        internal_storage = get_storage("watched")
         internal_storage[episode_id] = 1
         internal_storage[episode_id] = 1
         internal_storage.sync()
         internal_storage.sync()
 
 
         time = 0
         time = 0
+    else:
+        if episode_id in internal_storage:
+            del internal_storage[episode_id]
+            internal_storage.sync()
 
 
-        try:
-            __api__.__get__("set/watchedlist", __data__={
-                "id": episode_id,
-                "type": "episode"
-            })
+    success = True
 
 
-        except:
-            pass
+    try:
+        __api__.__get__("set/watchedlist", __data__={
+            "id": episode_id,
+            "value": int(seen),
+            "type": "episode"
+        })
+
+    except:
+        success = False
+        pass
 
 
     if time < 3 * 60:
     if time < 3 * 60:
         time = 0
         time = 0
@@ -364,6 +391,8 @@ def save_watchtime(episode_id, time=0, seen=False):
     internal_storage[episode_id] = time
     internal_storage[episode_id] = time
     internal_storage.sync()
     internal_storage.sync()
 
 
+    return success
+
 
 
 def read_watchtime(episode_id):
 def read_watchtime(episode_id):
     episode_id = str(episode_id)
     episode_id = str(episode_id)
@@ -395,15 +424,15 @@ def check_settings():
     if len(DEVICE_IDENTIFER) < 2 or (len(DEVICE_IDENTIFER) == 16 and is_hex(DEVICE_IDENTIFER)):
     if len(DEVICE_IDENTIFER) < 2 or (len(DEVICE_IDENTIFER) == 16 and is_hex(DEVICE_IDENTIFER)):
         # DEVICE_IDENTIFER = md5_string(str(randint(0, 99999)) + "" + str(int(time.time())))[:16]
         # DEVICE_IDENTIFER = md5_string(str(randint(0, 99999)) + "" + str(int(time.time())))[:16]
         try:
         try:
-            DEVICE_IDENTIFER = platform.system() + " " + platform.node() + " #" + str(random.randint(0, 99999))
+            DEVICE_IDENTIFER = platform.system() + " " + platform.node() + " " + str(random.randint(0, 99999))
         except:
         except:
-            DEVICE_IDENTIFER = "Maybe iOS " + sys.platform + " #" + str(random.randint(0, 99999))
+            DEVICE_IDENTIFER = "Maybe iOS " + sys.platform + " " + str(random.randint(0, 99999))
 
 
         PLUGIN.set_setting("deviceidentifier", DEVICE_IDENTIFER)
         PLUGIN.set_setting("deviceidentifier", DEVICE_IDENTIFER)
 
 
     internal_storage = get_storage("internal")
     internal_storage = get_storage("internal")
     # Version
     # Version
-    if "version" in internal_storage and internal_storage["version"] != PLUGIN.info("version"):
+    if "version" in internal_storage and internal_storage["version"] != PLUGIN_VERSION:
         if os.path.isfile(COOKIE_PATH):
         if os.path.isfile(COOKIE_PATH):
             try:
             try:
                 os.remove(COOKIE_PATH)
                 os.remove(COOKIE_PATH)
@@ -411,13 +440,14 @@ def check_settings():
                 pass
                 pass
 
 
         PLUGIN.notify("Es wurde eine neue Version installiert.")
         PLUGIN.notify("Es wurde eine neue Version installiert.")
+
         clear_session()
         clear_session()
 
 
         if DELETE_PASSWORD:
         if DELETE_PASSWORD:
             PLUGIN.set_setting("password", "")
             PLUGIN.set_setting("password", "")
             PLUGIN.dialog(u"Eine neue Version wurde installiert\nAus Sicherheitsgründen musst du dein Passwort neu eingeben.", "Information")
             PLUGIN.dialog(u"Eine neue Version wurde installiert\nAus Sicherheitsgründen musst du dein Passwort neu eingeben.", "Information")
 
 
-        internal_storage["version"] = PLUGIN.info("version")
+        internal_storage["version"] = PLUGIN_VERSION
         internal_storage.sync()
         internal_storage.sync()
 
 
     PORTAL_USERNAME = PLUGIN.get_setting("username")
     PORTAL_USERNAME = PLUGIN.get_setting("username")
@@ -466,7 +496,7 @@ def check_settings():
         pass
         pass
 
 
     internal_storage["hash"] = settings_hash_now
     internal_storage["hash"] = settings_hash_now
-    internal_storage["version"] = PLUGIN.info("version")
+    internal_storage["version"] = PLUGIN_VERSION
     internal_storage.sync()
     internal_storage.sync()
 
 
     return True
     return True
@@ -494,33 +524,34 @@ def empty():
 EMPTY_PATH = PLUGIN.url_for(endpoint="empty")
 EMPTY_PATH = PLUGIN.url_for(endpoint="empty")
 
 
 YOUTUBE_LIB_SEARCHED = False
 YOUTUBE_LIB_SEARCHED = False
-HAS_YOUTUBE_LIB = False
+HAS_YOUTUBE_LIB = xbmc.getCondVisibility("System.HasAddon(plugin.video.youtube)")
+HAS_DRM_LIB = xbmc.getCondVisibility("System.HasAddon(inputstream.adaptive)")
 
 
 
 
 def parse_youtube(trailer_id):
 def parse_youtube(trailer_id):
-    global YOUTUBE_LIB_SEARCHED, HAS_YOUTUBE_LIB
+    global HAS_YOUTUBE_LIB
+
+    if HAS_YOUTUBE_LIB:
+        output("YouTube library found")
+    else:
+        output("YouTube library not found!")
+
+    if not HAS_YOUTUBE_LIB:
+        return False
+
+    global YOUTUBE_LIB_SEARCHED
 
 
     if not YOUTUBE_LIB_SEARCHED:
     if not YOUTUBE_LIB_SEARCHED:
         YOUTUBE_LIB_SEARCHED = True
         YOUTUBE_LIB_SEARCHED = True
-        sys.path.append(os.path.realpath(os.path.join(PLUGIN_PATH, "..", "plugin.video.youtube", "resources")))
+        sys.path.append(os.path.realpath(os.path.join(PLUGIN_PATH, "..", "plugin.video.youtube", "resources", "lib")))
 
 
         try:
         try:
-            import lib.youtube_resolver
-
-            HAS_YOUTUBE_LIB = True
+            import youtube_resolver
         except:
         except:
             HAS_YOUTUBE_LIB = False
             HAS_YOUTUBE_LIB = False
 
 
-        if HAS_YOUTUBE_LIB:
-            output("YouTube library found")
-        else:
-            output("YouTube library not found!")
-
-    if not HAS_YOUTUBE_LIB:
-        return False
-
     output("Search for %s" % trailer_id)
     output("Search for %s" % trailer_id)
-    return lib.youtube_resolver.resolve(trailer_id)
+    return youtube_resolver.resolve(trailer_id)
 
 
 
 
 def master_lock_access(age):
 def master_lock_access(age):
@@ -560,7 +591,6 @@ def get_view(view_type="list"):
     return VIEW_IDS["skin.confluence"][0]
     return VIEW_IDS["skin.confluence"][0]
 
 
 
 
-import urllib
 import collections
 import collections
 
 
 OPENER = None
 OPENER = None
@@ -573,7 +603,7 @@ class __ApiRequest__(object):
         self._request = None
         self._request = None
 
 
         if OPENER is None:
         if OPENER is None:
-            OPENER = urllib2.build_opener(urllib2.HTTPCookieProcessor(CJ))
+            OPENER = urllib_request.build_opener(urllib_request.HTTPCookieProcessor())
             OPENER.addheaders = API_HEADERS
             OPENER.addheaders = API_HEADERS
 
 
         original_url = __url
         original_url = __url
@@ -590,17 +620,17 @@ class __ApiRequest__(object):
             if original_url != "auth":
             if original_url != "auth":
                 __data__["x"] = "%sFE%s" % (PORTAL_USERID, PORTAL_SESSION)
                 __data__["x"] = "%sFE%s" % (PORTAL_USERID, PORTAL_SESSION)
                 __data__["z"] = int(time.time())
                 __data__["z"] = int(time.time())
-                __data__["hash"] = md5_string("DEADBEEF%s?%s" % (original_url, urllib.urlencode(__data__)))
+                __data__["hash"] = md5_string("DEADBEEF%s?%s" % (original_url, urllib_parse.urlencode(__data__)))
 
 
-            __data__ = urllib.urlencode(__data__)
+            __data__ = urllib_parse.urlencode(__data__)
 
 
         if isinstance(__data__, str):
         if isinstance(__data__, str):
             __url = "%s?%s" % (__url, __data__)
             __url = "%s?%s" % (__url, __data__)
 
 
         __data__ = None
         __data__ = None
 
 
-        output("[API] Request: %s" % str(__url))
-        self._request = urllib2.Request(__url, __data__, __headers, __origin_req_host, __unverifiable)
+        output("---------------------------------------------------------------\n[API] Request: %s\n---------------------------------------------------------------" % str(__url))
+        self._request = urllib_request.Request(__url, __data__, __headers, __origin_req_host, __unverifiable)
 
 
     def __execute__(self):
     def __execute__(self):
         try:
         try:

+ 29 - 16
src/playserver.py

@@ -5,6 +5,12 @@ import time
 import xbmc
 import xbmc
 import traceback
 import traceback
 
 
+if sys.version_info[0] >= 3:
+    xrange = range
+
+else:
+    bytes = str
+
 
 
 def parse_episode(episode_id="0", first="0"):
 def parse_episode(episode_id="0", first="0"):
     first = 0
     first = 0
@@ -40,7 +46,7 @@ class __PlayServer__(object):
         self._started = False
         self._started = False
         self._last_progress = None
         self._last_progress = None
         self._exit_requested = False
         self._exit_requested = False
-        self._running_since = 0
+        self._last_file = 0
         self._times = {}
         self._times = {}
         self._player = xbmc.Player()
         self._player = xbmc.Player()
 
 
@@ -94,7 +100,7 @@ class __PlayServer__(object):
             if not request:
             if not request:
                 return False
                 return False
 
 
-            matches = re.search(r"^([^\s]+) /(.*(?=/))/[^\s]* HTTP", request, re.IGNORECASE | re.MULTILINE)
+            matches = re.search(r"^([^\s]+) /(.*(?=/))/[^\s]* HTTP", convert_to_str(request), re.IGNORECASE | re.MULTILINE)
             if matches:
             if matches:
                 method = matches.group(1)
                 method = matches.group(1)
                 params = matches.group(2).split("/")
                 params = matches.group(2).split("/")
@@ -105,14 +111,14 @@ class __PlayServer__(object):
 
 
                 if method == "HEAD":
                 if method == "HEAD":
                     if command == "play":
                     if command == "play":
-                        __client_socket__.send("HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\nConnection: close\r\n\r\n")
+                        __client_socket__.send(convert_to_bytes("HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\nConnection: close\r\n\r\n"))
 
 
                     elif command == "playlist":
                     elif command == "playlist":
-                        __client_socket__.send("HTTP/1.1 200 OK\r\nContent-Type: audio/x-mpegurl; charset=utf-8\r\nConnection: close\r\n\r\n")
+                        __client_socket__.send(convert_to_bytes("HTTP/1.1 200 OK\r\nContent-Type: audio/x-mpegurl; charset=utf-8\r\nConnection: close\r\n\r\n"))
 
 
                 else:
                 else:
                     if command == "exit":
                     if command == "exit":
-                        __client_socket__.send("HTTP/1.1 200 OK\r\nContent-Length: 2\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nOK")
+                        __client_socket__.send(convert_to_bytes("HTTP/1.1 200 OK\r\nContent-Length: 2\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nOK"))
                         self._exit_requested = True
                         self._exit_requested = True
                         output("[SERVER-" + str(self._port) + "] Playserver will be closed")
                         output("[SERVER-" + str(self._port) + "] Playserver will be closed")
                         self._running = False
                         self._running = False
@@ -146,11 +152,11 @@ class __PlayServer__(object):
                             tagline = unicode("%s" % (episode["title"] if season["title"] == "Default" else ("%s. %s" % (episode["number"], episode["title"]))))
                             tagline = unicode("%s" % (episode["title"] if season["title"] == "Default" else ("%s. %s" % (episode["number"], episode["title"]))))
                             title = "%s" % (unicode(tagline).replace(u"ä", "ae").replace(u"Ä", "Ae").replace(u"ö", "oe").replace(u"Ö", "Oe").replace(u"ü", "ue").replace(",", " "))
                             title = "%s" % (unicode(tagline).replace(u"ä", "ae").replace(u"Ä", "Ae").replace(u"ö", "oe").replace(u"Ö", "Oe").replace(u"ü", "ue").replace(",", " "))
                             playlist_content += "#EXTINF:-1,%s\n" % title
                             playlist_content += "#EXTINF:-1,%s\n" % title
-                            path = "http://127.0.0.1:%s/play/%s/%s.mkv" % (self._port, episode["id"], urllib.quote(title))
+                            path = "http://127.0.0.1:%s/play/%s/%s.mkv" % (self._port, episode["id"], urllib_parse.quote(title))
                             playlist_content += "%s\n" % path
                             playlist_content += "%s\n" % path
 
 
                         #__client_socket__.send("HTTP/1.1 200 OK\r\nContent-Type: application/x-mpegURL; charset=utf-8\r\nContent-Length: %s\r\nConnection: close\r\n\r\n%s" % (len(playlist_content), playlist_content))
                         #__client_socket__.send("HTTP/1.1 200 OK\r\nContent-Type: application/x-mpegURL; charset=utf-8\r\nContent-Length: %s\r\nConnection: close\r\n\r\n%s" % (len(playlist_content), playlist_content))
-                        __client_socket__.send("HTTP/1.1 200 OK\r\nContent-Type: audio/x-mpegurl; charset=utf-8\r\nContent-Length: %s\r\nConnection: close\r\n\r\n%s" % (len(playlist_content), playlist_content))
+                        __client_socket__.send(convert_to_bytes("HTTP/1.1 200 OK\r\nContent-Type: audio/x-mpegurl; charset=utf-8\r\nContent-Length: %s\r\nConnection: close\r\n\r\n%s" % (len(playlist_content), playlist_content)))
 
 
                     elif command == "play":
                     elif command == "play":
                         read_settings()
                         read_settings()
@@ -168,15 +174,15 @@ class __PlayServer__(object):
                                 raise Exception("Got no episode url")
                                 raise Exception("Got no episode url")
 
 
                             self._episode_id = episode_id
                             self._episode_id = episode_id
-                            __client_socket__.send("HTTP/1.1 301 Moved Permanently\r\nLocation: %s\r\nConnection: close\r\n\r\n" % episode_url)
+                            __client_socket__.send(convert_to_bytes("HTTP/1.1 301 Moved Permanently\r\nLocation: %s\r\nConnection: close\r\n\r\n" % episode_url))
 
 
-                        except Exception as e:
+                        except:
                             self._running = False
                             self._running = False
-                            output("[SERVER-" + str(self._port) + "] Client Play Error: %s" % traceback.format_exc())
+                            xbmc.log("[SERVER-" + str(self._port) + "] Client Play Error: %s" % traceback.format_exc(), level=xbmc.LOGERROR)
 
 
                             PLUGIN.notify("Fehler beim Abspielen!")
                             PLUGIN.notify("Fehler beim Abspielen!")
 
 
-                            raise e
+                            raise
 
 
                         finally:
                         finally:
                             hide_busy_dialog()
                             hide_busy_dialog()
@@ -192,10 +198,11 @@ class __PlayServer__(object):
             return True
             return True
 
 
         except:
         except:
-            __client_socket__.send("HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n")
+            __client_socket__.send(convert_to_bytes("HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n"))
 
 
             self._running = False
             self._running = False
-            output("[SERVER-" + str(self._port) + "] Client Error: %s" % traceback.format_exc())
+            xbmc.log("[SERVER-" + str(self._port) + "] Client Error: %s" % traceback.format_exc(), level=xbmc.LOGERROR)
+            PLUGIN.notify("Fehler beim Abspielen!")
 
 
             return False
             return False
 
 
@@ -281,7 +288,7 @@ class __PlayServer__(object):
         except:
         except:
             pass
             pass
 
 
-        if port:
+        if port and port is not None:
             try:
             try:
                 # Try to reach current running Server
                 # Try to reach current running Server
                 if socket.create_connection(("127.0.0.1", port), timeout=5):
                 if socket.create_connection(("127.0.0.1", port), timeout=5):
@@ -330,6 +337,8 @@ class __PlayServer__(object):
 
 
             output("[SERVER-" + str(self._port) + "] Started")
             output("[SERVER-" + str(self._port) + "] Started")
 
 
+            self._last_file = time.time()
+
             failed = 0
             failed = 0
             monitor = xbmc.Monitor()
             monitor = xbmc.Monitor()
             while True:
             while True:
@@ -373,9 +382,13 @@ class __PlayServer__(object):
                 is_playing = self._player.isPlayingVideo()
                 is_playing = self._player.isPlayingVideo()
                 if is_playing:
                 if is_playing:
                     current_file = self._player.getPlayingFile()
                     current_file = self._player.getPlayingFile()
+                    if current_file is not None and (":%s" % self._port) in current_file:
+                        self._last_file = time.time()
+                    else:
+                        current_file = None
 
 
-                aborted = monitor.abortRequested() > 0 or not self._running or self._exit_requested
-                output("[SERVER-" + str(self._port) + "] Idle abort: %s / file: %s" % (aborted, current_file))
+                aborted = monitor.abortRequested() > 0 or not self._running or self._exit_requested or (current_file is None and time.time() - self._last_file > 5 * 60)
+                output("[SERVER-" + str(self._port) + "] Idle abort: %s / File: %s / Last: %s" % (aborted, current_file, time.time() - self._last_file))
 
 
                 self.__track__(aborted)
                 self.__track__(aborted)
                 if aborted:
                 if aborted:

+ 399 - 78
src/plugin.py

@@ -1,11 +1,15 @@
 # -*- coding: utf-8 -*-
 # -*- coding: utf-8 -*-
+import base64
+import copy
 
 
-from api import *
 from consts import *
 from consts import *
+from utils import *
+from api import *
+
 import datetime
 import datetime
-import pprint
-import copy
-import urllib
+
+
+# xbmc.log(str(xbmc.getCondVisibility("System.GetBool(debug.showloginfo)")))
 
 
 
 
 @PLUGIN.route("/empty/", name="empty", update=False, cache=True)
 @PLUGIN.route("/empty/", name="empty", update=False, cache=True)
@@ -38,12 +42,12 @@ def play_trailer(trailer_id="", age=""):
         xbmc.log("[YOUTUBE] Error: %s" % traceback.format_exc())
         xbmc.log("[YOUTUBE] Error: %s" % traceback.format_exc())
 
 
         hide_busy_dialog()
         hide_busy_dialog()
-        PLUGIN.dialog("Es ist ein Fehler passiert bei YT:\n%s" % repr(e))
+        PLUGIN.dialog("Es ist ein Fehler passiert bei YT:\n%s" % str(e))
         return empty()
         return empty()
 
 
     if streams is False:
     if streams is False:
         hide_busy_dialog()
         hide_busy_dialog()
-        PLUGIN.dialog("Das Addon [B]plugin.video.youtube[/B] muss installiert sein")
+        PLUGIN.dialog("Das Addon [B]plugin.video.youtube[/B] muss installiert sein.")
         return empty()
         return empty()
 
 
     if not streams or len(streams) <= 0:
     if not streams or len(streams) <= 0:
@@ -59,17 +63,31 @@ def play_trailer(trailer_id="", age=""):
         "is_playable": True
         "is_playable": True
     }
     }
 
 
+    li = PLUGIN._listitemify(item).as_xbmc_listitem()
+    if stream["container"] == "mpd":
+        if not HAS_DRM_LIB:
+            hide_busy_dialog()
+            PLUGIN.dialog("Das Addon [B]inputstream.adaptive[/B] muss für diesen Trailer installiert sein.")
+            return empty()
+
+        if KODI_VERSION >= 19:
+            li.setProperty("inputstream", "inputstream.adaptive")
+        else:
+            li.setProperty("inputstreamaddon", "inputstream.adaptive")
+        li.setProperty("inputstream.adaptive.manifest_type", "mpd")
+        li.setMimeType("application/dash+xml")
+        li.setContentLookup(False)
+
+    elif stream["container"] in ["ism", "hls", "rtmp"]:
+        hide_busy_dialog()
+        PLUGIN.dialog("Container [B]%s[/B] wird nicht abspielbar!" % stream["container"])
+        return empty()
+
     playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
     playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
     playlist.clear()
     playlist.clear()
-
-    li = PLUGIN._listitemify(item).as_xbmc_listitem()
     playlist.add(item["path"], li)
     playlist.add(item["path"], li)
 
 
     player = xbmc.Player()
     player = xbmc.Player()
-
-    if False:
-        PLUGIN.notify("Trailer wird versucht abzuspielen!")
-
     player.play(playlist)
     player.play(playlist)
     del player
     del player
     player = None
     player = None
@@ -84,6 +102,8 @@ def view_actors(movie_id=0):
 
 
     items = []
     items = []
 
 
+    show_busy_dialog()
+
     movie_result = __api__.__get__("get/movie", __data__={
     movie_result = __api__.__get__("get/movie", __data__={
         "id": movie_id,
         "id": movie_id,
         "withActors": 1
         "withActors": 1
@@ -101,11 +121,11 @@ def view_actors(movie_id=0):
         return empty()
         return empty()
 
 
     items = [
     items = [
-        {
+        set_thumbnail({
             "label": unicode(entry["name"]),
             "label": unicode(entry["name"]),
             "path": PLUGIN.url_for(endpoint="view_actor",
             "path": PLUGIN.url_for(endpoint="view_actor",
                                    actor_id=entry['id'],
                                    actor_id=entry['id'],
-                                   page=0),
+                                   page=1),
             "thumbnail": get_poster_url(entry["profile"]),
             "thumbnail": get_poster_url(entry["profile"]),
             "info": {
             "info": {
                 "count": entry["id"],
                 "count": entry["id"],
@@ -114,17 +134,21 @@ def view_actors(movie_id=0):
             "is_playable": False,
             "is_playable": False,
             "context_menu": misc_menu(),
             "context_menu": misc_menu(),
             "replace_context_menu": True
             "replace_context_menu": True
-        } for idx, entry in enumerate(entries)
+        }) for idx, entry in enumerate(entries)
     ]
     ]
 
 
+    hide_busy_dialog()
+
     return items
     return items
 
 
 
 
 @PLUGIN.route("/view_actor/<actor_id>/<page>/", name="view_actor", cache=True, content_type="movies", view_mode=get_view("thumbnail"))
 @PLUGIN.route("/view_actor/<actor_id>/<page>/", name="view_actor", cache=True, content_type="movies", view_mode=get_view("thumbnail"))
-def view_actor(actor_id=0, page=0):
+def view_actor(actor_id=0, page=1):
     if not actor_id or actor_id == 0:
     if not actor_id or actor_id == 0:
         return empty()
         return empty()
 
 
+    show_busy_dialog()
+
     items = []
     items = []
 
 
     actor_result = __api__.__get__("get/actor", __data__={
     actor_result = __api__.__get__("get/actor", __data__={
@@ -133,17 +157,26 @@ def view_actor(actor_id=0, page=0):
     })
     })
 
 
     if not actor_result:
     if not actor_result:
+        hide_busy_dialog()
         return empty()
         return empty()
 
 
     items.extend(prepare_movies_to_list(actor_result["data"]["movies"]))
     items.extend(prepare_movies_to_list(actor_result["data"]["movies"]))
 
 
+    hide_busy_dialog()
+
     return items
     return items
 
 
 
 
 @PLUGIN.route("/search_trailer/<title>/<date>/<fanart>/<age>/", name="search_trailer", cache=False, content_type="episodes", view_mode=get_view("episode"))
 @PLUGIN.route("/search_trailer/<title>/<date>/<fanart>/<age>/", name="search_trailer", cache=False, content_type="episodes", view_mode=get_view("episode"))
 def search_trailer(title="", date="", fanart="", age=""):
 def search_trailer(title="", date="", fanart="", age=""):
+    if not HAS_YOUTUBE_LIB:
+        PLUGIN.dialog("Das Addon [B]plugin.video.youtube[/B] muss installiert sein.")
+        return empty()
+
     show_busy_dialog()
     show_busy_dialog()
+
     if not title or not master_lock_access(age):
     if not title or not master_lock_access(age):
+        hide_busy_dialog()
         return empty()
         return empty()
 
 
     year = re.search("([0-9]{4})-.*", date)
     year = re.search("([0-9]{4})-.*", date)
@@ -152,26 +185,40 @@ def search_trailer(title="", date="", fanart="", age=""):
     else:
     else:
         year = ""
         year = ""
 
 
-    title = urllib.pathname2url("%s trailer german deutsch" % (title.replace(":", "")))
+    title = pathname2url("%s trailer german deutsch" % (title.replace(":", "")))
 
 
-    if DEBUG:
-        output("[YOUTUBE]: %s" % (YOUTUBE_SEARCH_URL % title))
+    search_url = YOUTUBE_SEARCH_URL % (random.choice(YOUTUBE_KEYS), title)
 
 
+    #ifdef DEBUG
+    if DEBUG:
+        output("[YOUTUBE]: %s" % search_url)
+    #endif
     data = None
     data = None
     try:
     try:
-        data = urllib2.urlopen(YOUTUBE_SEARCH_URL % title).read()
-    except Exception as e:
-        output(repr(e))
+        data = urllib_request.urlopen(search_url).read()
+    except urllib_request.HTTPError as e:
+        data = e.read()
+    except:
+        output("[YOUTUBE] Exception: %s" % traceback.format_exc())
 
 
     if not data:
     if not data:
         hide_busy_dialog()
         hide_busy_dialog()
         PLUGIN.dialog("Fehler beim verarbeiten der Antwort.")
         PLUGIN.dialog("Fehler beim verarbeiten der Antwort.")
         return empty()
         return empty()
 
 
-    obj = string_to_json(data)
-    if not obj or not ('items' in obj):
+    try:
+        obj = string_to_json(data)
+    except:
+        obj = None
+
+    if not obj or 'items' not in obj:
         hide_busy_dialog()
         hide_busy_dialog()
-        PLUGIN.dialog("Es wurden keine Trailer gefunden")
+        if "error" in obj and len(obj["error"]["errors"]):
+            error = obj["error"]["errors"][0]
+            PLUGIN.dialog("Es ist ein Fehler passiert bei YT:\n%s" % error["reason"])
+        else:
+            PLUGIN.dialog("Es wurden keine Trailer gefunden")
+
         return empty()
         return empty()
 
 
     entries = obj['items']
     entries = obj['items']
@@ -181,14 +228,14 @@ def search_trailer(title="", date="", fanart="", age=""):
         return empty()
         return empty()
 
 
     items = [
     items = [
-        {
+        set_thumbnail({
             "label": unicode(entry['snippet']["title"]),
             "label": unicode(entry['snippet']["title"]),
             "path": PLUGIN.url_for(endpoint="play_trailer",
             "path": PLUGIN.url_for(endpoint="play_trailer",
                                    trailer_id=str(entry['id']['videoId']),
                                    trailer_id=str(entry['id']['videoId']),
                                    age="0"),
                                    age="0"),
             "thumbnail": entry['snippet']['thumbnails']['high']['url'].replace("https://", "http://"),
             "thumbnail": entry['snippet']['thumbnails']['high']['url'].replace("https://", "http://"),
             "properties": {
             "properties": {
-                "fanart_image": urllib.unquote(fanart) if fanart and fanart != "None" else "",
+                "fanart_image": urllib_parse.unquote(fanart) if fanart and fanart != "None" else "",
             },
             },
             "info": {
             "info": {
                 "count": entry["id"]["videoId"],
                 "count": entry["id"]["videoId"],
@@ -197,7 +244,7 @@ def search_trailer(title="", date="", fanart="", age=""):
                 "premiered": entry['snippet']["publishedAt"][:10] if entry['snippet']["publishedAt"] else ""
                 "premiered": entry['snippet']["publishedAt"][:10] if entry['snippet']["publishedAt"] else ""
             },
             },
             "is_playable": False,
             "is_playable": False,
-        } for idx, entry in enumerate(entries)
+        }) for idx, entry in enumerate(entries)
     ]
     ]
 
 
     hide_busy_dialog()
     hide_busy_dialog()
@@ -221,7 +268,7 @@ def watchlist_action(movie_id="0", action="add", refresh=0):
 
 
     message = None
     message = None
     if action == "add":
     if action == "add":
-        message = u"Eintrag wurde der Liste hinzugefügt"
+        message = "Eintrag wurde der Liste hinzugefuegt"
 
 
     elif action == "remove":
     elif action == "remove":
         message = "Eintrag wurde aus der Liste entfernt"
         message = "Eintrag wurde aus der Liste entfernt"
@@ -235,11 +282,26 @@ def watchlist_action(movie_id="0", action="add", refresh=0):
     return empty()
     return empty()
 
 
 
 
-@PLUGIN.route("/view_list/<list_type>/<page>/<view_types>/<genre>/<min_year>/<max_year>/<query>/", name="view_list", update=False, cache=True, content_type="movies", view_mode=get_view("thumbnail"))
+class UrlBasedCache():
+    def __trunc__(self):
+        try:
+            request = PLUGIN.request
+        except:
+            return True
+
+        do_cache = not ("/view_list/watched/" in request.url)
+        if not do_cache:
+            output("[PLUGIN] Cache will be ignored for %s" % request.url)
+        return do_cache
+
+
+@PLUGIN.route("/view_list/<list_type>/<page>/<view_types>/<genre>/<min_year>/<max_year>/<query>/", name="view_list", update=False, cache=UrlBasedCache(), content_type="movies", view_mode=get_view("thumbnail"))
 def view_list(list_type="new", view_types="0", page=1, genre="all", min_year=0, max_year=0, query=0):
 def view_list(list_type="new", view_types="0", page=1, genre="all", min_year=0, max_year=0, query=0):
     if str(view_types) == "2":
     if str(view_types) == "2":
         PLUGIN.set_goto_top(False)
         PLUGIN.set_goto_top(False)
 
 
+    show_busy_dialog()
+
     items = []
     items = []
 
 
     params = {
     params = {
@@ -251,18 +313,23 @@ def view_list(list_type="new", view_types="0", page=1, genre="all", min_year=0,
     }
     }
 
 
     if query != "0":
     if query != "0":
-        output("Search: %s" % query)
-        params["title"] = query
+        if sys.version_info.major < 3:
+            params["title"] = unicode(base64.b64decode(query), "utf-8").encode("utf-8")
+        else:
+            params["title"] = base64.b64decode(query)
 
 
     params["orderby"] = "updated_at|DESC"
     params["orderby"] = "updated_at|DESC"
     # params["orderby"] = "popularity|DESC"
     # params["orderby"] = "popularity|DESC"
 
 
     if view_types != "0":
     if view_types != "0":
-        params["types"] = view_types
+        params["types"] = view_types.replace("%2C", ",")
 
 
     if int(min_year) > 0 or int(max_year) > 0:
     if int(min_year) > 0 or int(max_year) > 0:
         params["year"] = "%s-%s" % (min_year, max_year)
         params["year"] = "%s-%s" % (min_year, max_year)
 
 
+    if genre != "all":
+        params["genres"] = genre
+
     result = __api__.__get__("get/list", __data__=params)
     result = __api__.__get__("get/list", __data__=params)
     if not result:
     if not result:
         hide_busy_dialog()
         hide_busy_dialog()
@@ -303,6 +370,8 @@ def view_list(list_type="new", view_types="0", page=1, genre="all", min_year=0,
 
 
         items.extend(pages)
         items.extend(pages)
 
 
+    hide_busy_dialog()
+
     return items
     return items
 
 
 
 
@@ -311,6 +380,8 @@ def search_similars(movie_id=0, page=1, type=0):
     if not movie_id:
     if not movie_id:
         return empty()
         return empty()
 
 
+    show_busy_dialog()
+
     result = __api__.__get__("get/similars", __data__={
     result = __api__.__get__("get/similars", __data__={
         "id": movie_id
         "id": movie_id
     })
     })
@@ -328,6 +399,8 @@ def search_similars(movie_id=0, page=1, type=0):
 
 
     items.extend(prepare_movies_to_list(result["data"]["results"]))
     items.extend(prepare_movies_to_list(result["data"]["results"]))
 
 
+    hide_busy_dialog()
+
     return items
     return items
 
 
 
 
@@ -440,8 +513,8 @@ def play_episode(episode_id=0, ask_playlist=0):
             else:
             else:
                 li["info"]["tagline"] = tagline
                 li["info"]["tagline"] = tagline
 
 
-        tit = unicode("%s" % (episode_result["data"]["season"]["title"] if episode_result["data"]["season"]["title"] == "Default" else ("%s. %s" % (episode["number"], episode["title"]))))
-        li["path"] = path = "http://127.0.0.1:%s/play/%s/%s.mkv" % (play_port, episode["id"], urllib.quote(tit))
+        tit = "File"  #unicode("%s" % (episode_result["data"]["season"]["title"] if episode_result["data"]["season"]["title"] == "Default" else ("%s. %s" % (episode["number"], episode["title"]))))
+        li["path"] = path = "http://127.0.0.1:%s/play/%s/%s.mkv" % (play_port, episode["id"], urllib_parse.quote(tit))
         li = PLUGIN._listitemify(li).as_xbmc_listitem()
         li = PLUGIN._listitemify(li).as_xbmc_listitem()
         playlist.add(path, li)
         playlist.add(path, li)
 
 
@@ -466,14 +539,15 @@ def play_episode(episode_id=0, ask_playlist=0):
                     else:
                     else:
                         li["info"]["tagline"] = tagline
                         li["info"]["tagline"] = tagline
 
 
-                tit = unicode("%s" % (episode_result["data"]["season"]["title"] if episode_result["data"]["season"]["title"] == "Default" else ("%s. %s" % (episode["number"], episode["title"]))))
-                li["path"] = path = "http://127.0.0.1:%s/play/%s/%s.mkv" % (play_port, episode["id"], urllib.quote(tit))
+                tit = "File"  #unicode("%s" % (episode_result["data"]["season"]["title"] if episode_result["data"]["season"]["title"] == "Default" else ("%s. %s" % (episode["number"], episode["title"]))))
+                li["path"] = path = "http://127.0.0.1:%s/play/%s/%s.mkv" % (play_port, episode["id"], urllib_parse.quote(tit))
                 li = PLUGIN._listitemify(li).as_xbmc_listitem()
                 li = PLUGIN._listitemify(li).as_xbmc_listitem()
                 playlist.add(path, li)
                 playlist.add(path, li)
 
 
         #ifdef DEBUG
         #ifdef DEBUG
         for idx in range(playlist.size()):
         for idx in range(playlist.size()):
-            output("[PLAY] %s - Item %s" % (idx, playlist[idx].getPath()))
+            path = playlist[idx].getPath() if hasattr(playlist[idx], "getPath") else playlist[idx].getfilename()
+            output("[PLAY] %s - Item %s" % (idx + 1, path))
         #endif
         #endif
 
 
         first = playlist[0]
         first = playlist[0]
@@ -493,9 +567,10 @@ def play_episode(episode_id=0, ask_playlist=0):
     player.play(playlist)
     player.play(playlist)
     del player
     del player
     player = None
     player = None
-
+    show_busy_dialog()
     xbmc.sleep(250)
     xbmc.sleep(250)
-    xbmc.executebuiltin("XBMC.Action(FullScreen)")
+    xbmc.executebuiltin("Action(FullScreen)")
+    show_busy_dialog()
 
 
     return empty()
     return empty()
 
 
@@ -504,6 +579,7 @@ def play_episode(episode_id=0, ask_playlist=0):
 def seasons(movie_id=0):
 def seasons(movie_id=0):
     show_busy_dialog()
     show_busy_dialog()
     if movie_id == 0:
     if movie_id == 0:
+        hide_busy_dialog()
         return empty()
         return empty()
 
 
     movie_result = __api__.__get__("get/movie", __data__={
     movie_result = __api__.__get__("get/movie", __data__={
@@ -528,7 +604,7 @@ def seasons(movie_id=0):
         return empty()
         return empty()
 
 
     items = [
     items = [
-        {
+        set_thumbnail({
             "label": unicode(season["title"]),
             "label": unicode(season["title"]),
             "path": PLUGIN.url_for(endpoint="episodes", season_id=season['id']),
             "path": PLUGIN.url_for(endpoint="episodes", season_id=season['id']),
             "thumbnail": get_poster_url(season["posterurl"] if season["posterurl"] else season_result["data"]["posterurl"]),
             "thumbnail": get_poster_url(season["posterurl"] if season["posterurl"] else season_result["data"]["posterurl"]),
@@ -546,7 +622,7 @@ def seasons(movie_id=0):
             },
             },
             "context_menu": misc_menu(),
             "context_menu": misc_menu(),
             "replace_context_menu": False
             "replace_context_menu": False
-        } for season in season_result["data"]["seasons"]
+        }) for season in season_result["data"]["seasons"]
     ]
     ]
 
 
     hide_busy_dialog()
     hide_busy_dialog()
@@ -558,6 +634,7 @@ def seasons(movie_id=0):
 def episodes(season_id=0, dialog=True):
 def episodes(season_id=0, dialog=True):
     show_busy_dialog()
     show_busy_dialog()
     if season_id == 0:
     if season_id == 0:
+        hide_busy_dialog()
         return empty()
         return empty()
 
 
     episode_results = __api__.__get__("get/season", __data__={
     episode_results = __api__.__get__("get/season", __data__={
@@ -572,7 +649,7 @@ def episodes(season_id=0, dialog=True):
         if not episode["id"]:
         if not episode["id"]:
             continue
             continue
 
 
-        items.append({
+        items.append(set_thumbnail({
             "label": "%s. %s" % (episode["number"], unicode(episode["title"])),
             "label": "%s. %s" % (episode["number"], unicode(episode["title"])),
             "path": PLUGIN.url_for(endpoint="play_episode",
             "path": PLUGIN.url_for(endpoint="play_episode",
                                    episode_id=episode['id'],
                                    episode_id=episode['id'],
@@ -580,7 +657,7 @@ def episodes(season_id=0, dialog=True):
             "is_playable": False,
             "is_playable": False,
             "thumbnail": get_scene_url(episode["posterurl"] if episode["posterurl"] else None),
             "thumbnail": get_scene_url(episode["posterurl"] if episode["posterurl"] else None),
             "properties": {
             "properties": {
-                # "fanart_image": get_backdrop_url(obj["data"]["movie"]['backdropurl']),
+                #"fanart_image": get_backdrop_url(episode_results["data"]['backdropurl']),
             },
             },
             "info": {
             "info": {
                 "plot": unicode(episode["description"]) if episode["description"] else (unicode(episode_results["data"]["description"]) if episode_results["data"]["description"] else None),
                 "plot": unicode(episode["description"]) if episode["description"] else (unicode(episode_results["data"]["description"]) if episode_results["data"]["description"] else None),
@@ -593,31 +670,57 @@ def episodes(season_id=0, dialog=True):
             },
             },
             "context_menu": misc_menu(episode_id=episode["id"]),
             "context_menu": misc_menu(episode_id=episode["id"]),
             "replace_context_menu": False
             "replace_context_menu": False
-        })
+        }))
 
 
     hide_busy_dialog()
     hide_busy_dialog()
 
 
     return items
     return items
 
 
 
 
-@PLUGIN.route("/mark_as_seen/<episodeid>/", name="mark_as_seen")
-def mark_as_seen(episodeid="0"):
+@PLUGIN.route("/mark_as_seen/<episodeid>/<seen>/", name="mark_as_seen")
+def mark_as_seen(episodeid="0", seen="0"):
     if not episodeid or episodeid == "0":
     if not episodeid or episodeid == "0":
-        return None
+        return empty()
+
+    show_busy_dialog()
+
+    if not save_watchtime(episodeid, time=0, seen=int(seen)):
+        hide_busy_dialog()
+        PLUGIN.notify("Fehler beim ausfuehren der Aktion!")
+    else:
+        hide_busy_dialog()
+        PLUGIN.notify("Eintrag wurde als %sgesehen markiert." % ("un" if not int(seen) else ""))
 
 
     return None
     return None
 
 
 
 
 @PLUGIN.route("/account_status/", name="account_status")
 @PLUGIN.route("/account_status/", name="account_status")
 def account_status():
 def account_status():
-    return empty()
+    userinfo_result = __api__.__get__("get/userinfo")
+
+    if not userinfo_result:
+        hide_busy_dialog()
+        PLUGIN.dialog("Fehler beim verarbeiten der Antwort.")
+        return empty()
+
+    data = userinfo_result["data"]
+    text = ""
+    if data and "abonnement" in data:
+        text += "[B]Laufzeit:[/B]\n\n"
+        text += "%s - %s" % (data["abonnement"]["start"]["date"], data["abonnement"]["end"]["date"])
+    else:
+        text = u"Keine Informationen bezüglich Laufzeit."
+
+    hide_busy_dialog()
+    PLUGIN.dialog(text)
+    return None
 
 
 
 
 @PLUGIN.route("/clear_password/", name="clear_password")
 @PLUGIN.route("/clear_password/", name="clear_password")
 def clear_password():
 def clear_password():
     clear_session()
     clear_session()
     PLUGIN.set_setting("password", "")
     PLUGIN.set_setting("password", "")
-    return empty()
+    return None
 
 
 
 
 @PLUGIN.route("/clear_storage/", name="clear_storage")
 @PLUGIN.route("/clear_storage/", name="clear_storage")
@@ -627,29 +730,106 @@ def clear_storage():
     clear_session()
     clear_session()
 
 
     PLUGIN.notify("Storage wurde geleert.")
     PLUGIN.notify("Storage wurde geleert.")
-    return empty()
+    return None
 
 
 
 
-@PLUGIN.route("/search/<is_actor>/", name="search", cache=False)
-def search(is_actor="0"):
-    is_actor = 0
+@PLUGIN.route("/fuckinghell/<is_actor>/", name="fuckinghell", cache=False)
+def fuckinghell(is_actor="0"):
+    is_actor = str(is_actor)
 
 
     title = "Schauspieler" if is_actor == "1" else "Film oder Serie"
     title = "Schauspieler" if is_actor == "1" else "Film oder Serie"
     query = PLUGIN.keyboard('', "Nach %s Suchen" % title)
     query = PLUGIN.keyboard('', "Nach %s Suchen" % title)
 
 
     if query:
     if query:
-        return PLUGIN.redirect(PLUGIN.url_for(endpoint="view_list",
-                                              list_type="all",
-                                              view_types=VIEW_TYPES,
-                                              genre="all",
-                                              min_year=0,
-                                              max_year=0,
-                                              query=query,
-                                              page=1))
+        query = base64.b64encode(convert_to_bytes(query))
+        if is_actor == "1":
+            return PLUGIN.redirect(PLUGIN.url_for(endpoint="search_actors",
+                                                  query=query,
+                                                  page=1))
+
+        else:
+            return PLUGIN.redirect(PLUGIN.url_for(endpoint="view_list",
+                                                  list_type="all",
+                                                  view_types=VIEW_TYPES,
+                                                  genre="all",
+                                                  min_year=0,
+                                                  max_year=0,
+                                                  query=query,
+                                                  page=1))
 
 
     return empty()
     return empty()
 
 
 
 
+@PLUGIN.route("/search_actors/<query>/<page>/", name="search_actors", cache=True, content_type="movies", view_mode=get_view("thumbnail"), goto_top=True)
+def search_actors(query="", page=1):
+    if not query:
+        return empty()
+
+    show_busy_dialog()
+
+    if sys.version_info.major < 3:
+        encoded_query = unicode(base64.b64decode(query), "utf-8").encode("utf-8")
+    else:
+        encoded_query = base64.b64decode(query)
+
+    result = __api__.__get__("get/actors", __data__={
+        "query": encoded_query,
+        "page": page,
+        "limit": MOVIES_PER_PAGE,
+        "extended": 0
+    })
+
+    if not result:
+        hide_busy_dialog()
+        PLUGIN.notify("Fehler beim verarbeiten der Anfrage.")
+        return empty()
+
+    if result["data"]["total_results"] <= 0:
+        hide_busy_dialog()
+        PLUGIN.dialog(u"Leider wurden keine Einträge gefunden!")
+        return empty()
+
+    items = []
+
+    actors = result["data"]["results"]
+
+    for actor in actors:
+        items.append(set_thumbnail({
+            "label": actor["name"].strip(),
+            "thumbnail": get_poster_url(actor["picture"]) if actor["picture"] else "",
+            "path": PLUGIN.url_for(endpoint="view_actor",
+                                   actor_id=actor["id"],
+                                   page=1),
+            "context_menu": misc_menu(),
+            "replace_context_menu": False
+        }))
+
+    total = result["data"]["total_pages"]
+    if total > 1:
+        pages = []
+        for pagenum in range(1, total + 1):
+            pages.append(
+                {
+                    "label": ("[COLOR red][B][I]Seite %s von %s[/I][/B][/COLOR]" % (pagenum, total)) if int(pagenum) == int(page) else "Seite %s von %s" % (pagenum, total),
+                    "is_playable": False,
+                    "path": EMPTY_PATH if int(pagenum) == int(page) else PLUGIN.url_for(endpoint="search_actors",
+                                                                                        page=pagenum,
+                                                                                        query=query),
+                    "info": {
+                        "playcount": 1 if int(pagenum) == int(page) else 0,
+                        "tagline": "[B]%s[/B] bis [B]%s[/B]" % (unicode(pagenum * int(result["data"]["limit"])), unicode(min(pagenum * int(result["data"]["limit"]), total)))
+                    },
+                    "context_menu": misc_menu(),
+                    "replace_context_menu": False
+                }
+            )
+
+        items.extend(pages)
+
+    hide_busy_dialog()
+    return items
+
+
 @PLUGIN.route("/open_settings/", name="open_settings", cache=True)
 @PLUGIN.route("/open_settings/", name="open_settings", cache=True)
 def open_settings():
 def open_settings():
     PLUGIN.open_settings()
     PLUGIN.open_settings()
@@ -673,8 +853,8 @@ def account_logout():
 @PLUGIN.route("/stop_playserver/", name="stop_playserver", cache=False)
 @PLUGIN.route("/stop_playserver/", name="stop_playserver", cache=False)
 def stop_playserver():
 def stop_playserver():
     server = get_storage("server")
     server = get_storage("server")
-    if server is None or not ("port" in server) or server["port"] == 0:
-        PLUGIN.notify(u"Playserver läuft nicht!")
+    if server is None or "port" not in server or server["port"] == 0:
+        PLUGIN.notify("Playserver laeuft nicht!")
 
 
     else:
     else:
         try:
         try:
@@ -695,7 +875,141 @@ def stop_playserver():
     return empty()
     return empty()
 
 
 
 
-# Main
+@PLUGIN.route("/view_filters/", name="view_filters", cache=True, content_type="files", view_mode=get_view("list"))
+def view_filters():
+    items = []
+
+    items.append({
+        "label": "Nach Genre",
+        "path": PLUGIN.url_for(endpoint="filter_genre"),
+    })
+    items.append({
+        "label": "Nach Jahr",
+        "path": PLUGIN.url_for(endpoint="filter_years"),
+    })
+
+    return items
+
+
+@PLUGIN.route("/filter_genre/", name="filter_genre", cache=True, content_type="files", view_mode=get_view("list"))
+def filter_genre():
+    show_busy_dialog()
+    items = []
+
+    result = __api__.__get__("get/genres", __data__={
+        "page": 1,
+        "limit": 9999999
+    })
+
+    if not result:
+        hide_busy_dialog()
+        PLUGIN.notify("Fehler beim verarbeiten der Anfrage.")
+        return empty()
+
+    if len(result["data"]) <= 0:
+        hide_busy_dialog()
+        PLUGIN.dialog(u"Leider wurden keine Genres gefunden!")
+        return empty()
+
+    for genre in result["data"]:
+        items.append({
+            "label": "%s (%s)" % (genre["name"], genre["movies"]),
+            "path": PLUGIN.url_for(endpoint="view_list",
+                                   genre=genre["name"],
+                                   list_type="all",
+                                   view_types=VIEW_TYPES,
+                                   page=1,
+                                   query=0,
+                                   min_year=0,
+                                   max_year=0),
+        })
+
+    hide_busy_dialog()
+    return items
+
+
+@PLUGIN.route("/filter_years_manually/", name="filter_years_manually", cache=False)
+def search():
+    query = PLUGIN.keyboard('', "Jahr eingeben")
+
+    if query:
+        min_year = query
+        max_year = query
+        if "-" in query:
+            chunks = query.split("-")
+            min_year = chunks[0].strip()
+            max_year = chunks[1].strip()
+
+        if not min_year.isdigit() or not max_year.isdigit():
+            PLUGIN.dialog(u"Jahr nicht gültig!\nBeispiele:\n- 1950\n- 1900-1950")
+            return empty()
+
+        return PLUGIN.redirect(PLUGIN.url_for(endpoint="view_list",
+                                              genre="all",
+                                              list_type="all",
+                                              view_types=VIEW_TYPES,
+                                              page=1,
+                                              query=0,
+                                              min_year=min_year,
+                                              max_year=max_year))
+
+    return empty()
+
+
+@PLUGIN.route("/filter_years/", name="filter_years", cache=True, content_type="files", view_mode=get_view("list"), goto_top=False)
+def filter_years():
+    year = datetime.datetime.now().year
+
+    current_year = year
+    year_range = 0
+
+    items = []
+    while year - year_range >= 1949:
+        diff = current_year - year
+        if diff < 5:
+            year_range = 1
+        elif diff <= 10:
+            year_range = 5
+        else:
+            year_range = 10
+
+        min_year = (year - year_range + 1) if year_range != 1 else year
+        max_year = year
+
+        items.append({
+            "label": ("%s - %s" % (year - year_range + 1, year)) if year_range != 1 else str(year),
+            "path": PLUGIN.url_for(endpoint="view_list",
+                                   genre="all",
+                                   list_type="all",
+                                   view_types=VIEW_TYPES,
+                                   page=1,
+                                   query=0,
+                                   min_year=min_year,
+                                   max_year=max_year)
+        })
+
+        year -= year_range
+
+    if year >= 1950:
+        diff = year - 1950
+        items.append({
+            "label": ("1950 - %s" % year) if diff > 1 else "1950",
+            "path": PLUGIN.url_for(endpoint="view_list",
+                                   genre="all",
+                                   list_type="all",
+                                   view_types=VIEW_TYPES,
+                                   page=1,
+                                   query=0,
+                                   min_year=1950,
+                                   max_year=year if diff > 1 else 1950)
+        })
+
+    items.append({
+        "label": "Jahr manuell eingeben",
+        "path": PLUGIN.url_for(endpoint="filter_years_manually"),
+    })
+
+    return items
 
 
 
 
 @PLUGIN.route("/updated_needed/", name="updated_needed", cache=True)
 @PLUGIN.route("/updated_needed/", name="updated_needed", cache=True)
@@ -704,6 +1018,7 @@ def updated_needed():
     return items
     return items
 
 
 
 
+# Main
 @PLUGIN.route("/", name="main", update=True, cache=False, content_type="files", view_mode=get_view("list"), goto_top=False)
 @PLUGIN.route("/", name="main", update=True, cache=False, content_type="files", view_mode=get_view("list"), goto_top=False)
 def main():
 def main():
     items = []
     items = []
@@ -738,19 +1053,18 @@ def main():
         if True:
         if True:
             items.append({
             items.append({
                 "label": "Suche Film oder Serie",
                 "label": "Suche Film oder Serie",
-                "path": PLUGIN.url_for(endpoint="search",
-                                       is_actor=0),
+                "path": PLUGIN.url_for(endpoint="fuckinghell",
+                                       is_actor="0"),
                 "context_menu": [
                 "context_menu": [
                     ("", "")
                     ("", "")
                 ],
                 ],
                 "replace_context_menu": True,
                 "replace_context_menu": True,
             })
             })
 
 
-        if False:
             items.append({
             items.append({
                 "label": "Suche Schauspieler",
                 "label": "Suche Schauspieler",
-                "path": PLUGIN.url_for(endpoint="search",
-                                       is_actor=1),
+                "path": PLUGIN.url_for(endpoint="fuckinghell",
+                                       is_actor="1"),
                 "context_menu": [
                 "context_menu": [
                     ("", "")
                     ("", "")
                 ],
                 ],
@@ -761,8 +1075,6 @@ def main():
             if WATCHLIST_TOGETHER:
             if WATCHLIST_TOGETHER:
                 items.append({
                 items.append({
                     "label": "Meine Liste",
                     "label": "Meine Liste",
-                    # "path": PLUGIN.url_for(endpoint="watchlist", page=1, type="0")
-
                     "path": PLUGIN.url_for(endpoint="view_list",
                     "path": PLUGIN.url_for(endpoint="view_list",
                                            list_type="watchlist",
                                            list_type="watchlist",
                                            view_types=VIEW_TYPES,
                                            view_types=VIEW_TYPES,
@@ -776,7 +1088,6 @@ def main():
             else:
             else:
                 items.append({
                 items.append({
                     "label": "Meine Filme",
                     "label": "Meine Filme",
-                    # "path": PLUGIN.url_for(endpoint="watchlist", page=1, type="1|3|4")
                     "path": PLUGIN.url_for(endpoint="view_list",
                     "path": PLUGIN.url_for(endpoint="view_list",
                                            list_type="watchlist-movies",
                                            list_type="watchlist-movies",
                                            view_types=VIEW_TYPES,
                                            view_types=VIEW_TYPES,
@@ -788,7 +1099,6 @@ def main():
                 })
                 })
                 items.append({
                 items.append({
                     "label": "Meine Serien",
                     "label": "Meine Serien",
-                    # "path": PLUGIN.url_for(endpoint="watchlist", page=1, type="2|5")
                     "path": PLUGIN.url_for(endpoint="view_list",
                     "path": PLUGIN.url_for(endpoint="view_list",
                                            list_type="watchlist-shows",
                                            list_type="watchlist-shows",
                                            view_types=VIEW_TYPES,
                                            view_types=VIEW_TYPES,
@@ -850,7 +1160,7 @@ def main():
                                        max_year=0)
                                        max_year=0)
             })
             })
 
 
-            if False:
+            if not HIDE_SERIES:
                 items.append({
                 items.append({
                     "label": "UHD Serien",
                     "label": "UHD Serien",
                     "path": PLUGIN.url_for(endpoint="view_list",
                     "path": PLUGIN.url_for(endpoint="view_list",
@@ -858,8 +1168,8 @@ def main():
                                            list_type="uhd-shows",
                                            list_type="uhd-shows",
                                            view_types="5",
                                            view_types="5",
                                            page=1,
                                            page=1,
-                                           min_year=0,
                                            query=0,
                                            query=0,
+                                           min_year=0,
                                            max_year=0)
                                            max_year=0)
                 })
                 })
 
 
@@ -878,7 +1188,7 @@ def main():
 
 
         if not HIDE_SERIES:
         if not HIDE_SERIES:
             items.append({
             items.append({
-                "label": "Serien",
+                "label": "HD Serien",
                 "path": PLUGIN.url_for(endpoint="view_list",
                 "path": PLUGIN.url_for(endpoint="view_list",
                                        genre="all",
                                        genre="all",
                                        list_type="new-episodes",
                                        list_type="new-episodes",
@@ -914,6 +1224,11 @@ def main():
                                    max_year=0)
                                    max_year=0)
         })
         })
 
 
+        items.append({
+            "label": "Filter",
+            "path": PLUGIN.url_for(endpoint="view_filters"),
+        })
+
         if not HIDE_SETTINGS:
         if not HIDE_SETTINGS:
             items.append({
             items.append({
                 "label": "Einstellungen",
                 "label": "Einstellungen",
@@ -939,6 +1254,9 @@ def main():
 
 
 # --------------------------------
 # --------------------------------
 
 
+__version__ = PLUGIN_VERSION
+__all__ = ["__run", "__output", "__version__"]
+
 
 
 def __run():
 def __run():
     output("==================================== START ====================================")
     output("==================================== START ====================================")
@@ -954,7 +1272,7 @@ def __run():
 
 
         try:
         try:
             os.chdir(os.path.dirname(os.path.abspath(__file__)))
             os.chdir(os.path.dirname(os.path.abspath(__file__)))
-            if str(__file__).endswith(".py"):
+            if str(__file__).endswith(".py") and os.path.exists("%s.pyo" % __file__):
                 xbmc.sleep(100)
                 xbmc.sleep(100)
                 import glob
                 import glob
                 for file in glob.glob("framework/*.py"):
                 for file in glob.glob("framework/*.py"):
@@ -962,5 +1280,8 @@ def __run():
                 os.remove(__file__)
                 os.remove(__file__)
 
 
         except Exception as e:
         except Exception as e:
+            #ifdef DEBUG
             if DEBUG:
             if DEBUG:
                 output("Exception: %s" % repr(e))
                 output("Exception: %s" % repr(e))
+            #endif
+            pass

+ 107 - 48
src/utils.py

@@ -3,12 +3,23 @@ import hashlib
 import re
 import re
 import os
 import os
 import sys
 import sys
+import pprint
+import xbmc
 import platform
 import platform
+from consts import *
+
+if sys.version_info[0] >= 3:
+    unicode = str
+    long = int
+
+
+def string_str(s):
+    return s
 
 
 
 
 def md5_string(i):
 def md5_string(i):
     m = hashlib.md5()
     m = hashlib.md5()
-    m.update(i)
+    m.update(i.encode("utf-8"))
     return m.hexdigest()
     return m.hexdigest()
 
 
 
 
@@ -16,19 +27,22 @@ def md5_file(fname):
     hash_md5 = hashlib.md5()
     hash_md5 = hashlib.md5()
     with open(fname, "rb") as f:
     with open(fname, "rb") as f:
         for chunk in iter(lambda: f.read(4096), b""):
         for chunk in iter(lambda: f.read(4096), b""):
-            hash_md5.update(chunk)
+            hash_md5.update(chunk.encode("utf-8"))
     return hash_md5.hexdigest()
     return hash_md5.hexdigest()
 
 
 
 
 def string_to_json(i):
 def string_to_json(i):
-    return json.loads(i)
+    try:
+        return json.loads(i)
+    except:
+        return None
 
 
 
 
 def is_hex(val):
 def is_hex(val):
     try:
     try:
         int(val, 16)
         int(val, 16)
         return True
         return True
-    except ValueError, e:
+    except ValueError:
         return False
         return False
 
 
 
 
@@ -104,7 +118,7 @@ def format_seconds_to_hhmmss(seconds):
     return "%02i:%02i:%02i" % (hours, minutes, seconds)
     return "%02i:%02i:%02i" % (hours, minutes, seconds)
 
 
 
 
-def misc_menu(data=None, episode_id=None):
+def misc_menu(menu=None, data=None, episode_id=None):
     """
     """
 
 
     @param data:
     @param data:
@@ -112,36 +126,36 @@ def misc_menu(data=None, episode_id=None):
     @return:
     @return:
     """
     """
 
 
-    if not data:
-        data = []
+    if not menu:
+        menu = []
 
 
-    if False and episode_id:
-        data.append(
+    if True and episode_id and data:
+        menu.append(
             (
             (
-                "Als gesehen markieren",
-                'RunPlugin("%s")' % PLUGIN.url_for(endpoint="mark_as_seen", episodeid=episode_id)
+                "Als %sgesehen markieren" % ("un" if data["in_watchedlist"] else ""),
+                'RunPlugin("%s")' % PLUGIN.url_for(endpoint="mark_as_seen", episodeid=episode_id, seen=int(not data["in_watchedlist"]))
             )
             )
         )
         )
 
 
-    data.append(
+    menu.append(
         (
         (
             "Zum Listenanfang",
             "Zum Listenanfang",
-            "XBMC.Action(firstpage)"
+            "Action(firstpage)"
         )
         )
     )
     )
-    data.append(
+    menu.append(
         (
         (
             u"Zum Hauptmenü",
             u"Zum Hauptmenü",
-            'XBMC.Container.Update("%s",replace)' % PLUGIN.url_for(endpoint="main")
+            'Container.Update("%s",replace)' % PLUGIN.url_for(endpoint="main")
         )
         )
     )
     )
-    data.append(
+    menu.append(
         (
         (
             u"Ebene zurück",
             u"Ebene zurück",
-            'XBMC.Action(Back)'
+            'Action(Back)'
         )
         )
     )
     )
-    return data
+    return menu
 
 
 
 
 def has_played(movie_id=0):
 def has_played(movie_id=0):
@@ -182,7 +196,47 @@ def get_user_agent():
     return user_agent
     return user_agent
 
 
 
 
-import pprint
+def convert_to_bytes(text, encoding="utf-8"):
+    if sys.version_info.major < 3:
+        return text
+    else:
+        try:
+            return text.encode(encoding, "ignore")
+        except Exception:
+            return text
+
+
+def convert_to_str(text, encoding="utf-8"):
+    if sys.version_info.major < 3:
+        return text
+    else:
+        try:
+            return text.decode(encoding, "ignore")
+        except Exception:
+            return text
+
+
+def set_thumbnail(item):
+    if "art" not in item or not isinstance(item["art"], dict):
+        item["art"] = {}
+
+    thumbnail = item.get("thumbnail")
+    fanart = item.get("properties", {}).get("thumbnail")
+
+    if fanart is not None:
+        item["art"]["fanart"] = fanart
+
+    if thumbnail is not None:
+        item["art"]["thumb"] = thumbnail
+        item["art"]["landscape"] = item["art"]["thumb"]
+        item["art"]["icon"] = item["art"]["thumb"]
+        item["art"]["clearlogo"] = item["art"]["thumb"]
+        item["art"]["banner"] = item["art"]["thumb"]
+        """
+        item["art"]["poster"] = item["art"]["thumb"]
+        """
+
+    return item
 
 
 
 
 def prepare_entry(entry, isfirst=False, prefixed=True):
 def prepare_entry(entry, isfirst=False, prefixed=True):
@@ -192,15 +246,13 @@ def prepare_entry(entry, isfirst=False, prefixed=True):
     trailer_id = None
     trailer_id = None
     if entry["trailer"]:
     if entry["trailer"]:
         # trailer_id = re.match(r'^[^v]+v[/=](.{3,11}).*', entry["trailer"])
         # trailer_id = re.match(r'^[^v]+v[/=](.{3,11}).*', entry["trailer"])
-        trailer_id = re.search(r"(?:v=|//[^/]+\.be/)(.{3,11})", entry["trailer"].encode('ascii', 'ignore'))
+        trailer_id = re.search(r"(?:v=|//[^/]+\.be/)(.{3,11})", entry["trailer"])
         if trailer_id:
         if trailer_id:
             trailer_id = trailer_id.group(1)
             trailer_id = trailer_id.group(1)
 
 
     fanart_url = get_backdrop_url(entry["backdropurl"])
     fanart_url = get_backdrop_url(entry["backdropurl"])
 
 
-    entry["title"] = u''.join((unicode(entry["title"]), u"")).encode("utf-8").strip()
-
-    title = entry['title'].decode("utf-8")
+    title = unicode(entry['title'])
     if prefixed:
     if prefixed:
         if entry["type"] == 1:
         if entry["type"] == 1:
             title = "HD: %s" % title
             title = "HD: %s" % title
@@ -229,7 +281,7 @@ def prepare_entry(entry, isfirst=False, prefixed=True):
     menu = [
     menu = [
         (
         (
             "Informationen",
             "Informationen",
-            "XBMC.Action(Info)"
+            "Action(Info)"
         )
         )
     ]
     ]
 
 
@@ -250,19 +302,19 @@ def prepare_entry(entry, isfirst=False, prefixed=True):
         menu.append(
         menu.append(
             (
             (
                 "Schauspieler anzeigen",
                 "Schauspieler anzeigen",
-                'XBMC.Container.Update("%s",True)' % PLUGIN.url_for(endpoint="view_actors",
-                                                                    movie_id=entry['id'])
+                'Container.Update("%s",True)' % PLUGIN.url_for(endpoint="view_actors",
+                                                               movie_id=entry['id'])
             )
             )
         )
         )
 
 
     menu.append(
     menu.append(
         (
         (
             "%sTrailer suchen" % ("weitere " if trailer_id else ""),
             "%sTrailer suchen" % ("weitere " if trailer_id else ""),
-            'XBMC.Container.Update("%s",True)' % PLUGIN.url_for(endpoint="search_trailer",
-                                                                title=entry['title'],
-                                                                date="%s" % entry['release_date'],
-                                                                fanart=fanart_url if fanart_url else "None",
-                                                                age=entry["age"] if "age" in entry and entry["age"] else "0")
+            'Container.Update("%s",True)' % PLUGIN.url_for(endpoint="search_trailer",
+                                                           title=entry['title'] if isinstance(entry["title"], int) else entry['title'].encode("utf-8"),
+                                                           date="%s" % entry['release_date'],
+                                                           fanart=fanart_url if fanart_url else "None",
+                                                           age=entry["age"] if "age" in entry and entry["age"] else "0")
         )
         )
     )
     )
 
 
@@ -290,7 +342,18 @@ def prepare_entry(entry, isfirst=False, prefixed=True):
             )
             )
         )
         )
 
 
-    watched = (entry["in_watchedlist"] * 1) if "in_watchedlist" in entry else (has_played(entry['episode_id']) if entry["has_episodes"] == False else 0)
+    if False and entry["collection"]:
+        menu.append(
+            (
+                "Filmreihe anzeigen",
+                'Container.Update("%s",True)' % PLUGIN.url_for(endpoint="search_similars",
+                                                               movie_id="%s" % entry['id'],
+                                                               page=0,
+                                                               type=entry["type"])
+            )
+        )
+
+    watched = (entry["in_watchedlist"] * 1) if "in_watchedlist" in entry else (has_played(entry['episode_id']) if not entry["has_episodes"] else 0)
 
 
     item = {
     item = {
         "label": title,
         "label": title,
@@ -317,9 +380,9 @@ def prepare_entry(entry, isfirst=False, prefixed=True):
             "director": None,
             "director": None,
             "genre": entry["genres"],
             "genre": entry["genres"],
             "date": entry["release_date"] if entry["release_date"] else None,
             "date": entry["release_date"] if entry["release_date"] else None,
-            "title": entry['title'].decode("utf-8"),
+            "title": unicode(entry['title']),
             "originaltitle": unicode(entry["original_title"]) if entry["original_title"] else None,
             "originaltitle": unicode(entry["original_title"]) if entry["original_title"] else None,
-            "tagline": (u"[I]%s[/I]  - %s" % (entry["year"], entry["genres"])) if USE_TAGLINE else None,
+            "tagline": (u"%s  - %s" % (entry["year"], entry["genres"])) if USE_TAGLINE else None,
             "trailer": play_trailer,
             "trailer": play_trailer,
             "duration": ("%s" % (int(entry["runtime"]) * 60)) if entry["runtime"] else None,
             "duration": ("%s" % (int(entry["runtime"]) * 60)) if entry["runtime"] else None,
             "imdbnumber": entry["imdb_id"] if entry["imdb_id"] else None,
             "imdbnumber": entry["imdb_id"] if entry["imdb_id"] else None,
@@ -327,23 +390,14 @@ def prepare_entry(entry, isfirst=False, prefixed=True):
         },
         },
         "stream_info": {
         "stream_info": {
             "video": {
             "video": {
-                # "codec": "h264",
                 "duration": ("%s" % (int(entry["runtime"]) * 60)) if entry["runtime"] else None,
                 "duration": ("%s" % (int(entry["runtime"]) * 60)) if entry["runtime"] else None,
             }
             }
         },
         },
-        "context_menu": misc_menu(menu, episode_id=entry['episode_id'] if entry["has_episodes"] == False else None),
+        "context_menu": misc_menu(menu, data=entry, episode_id=entry['episode_id'] if not entry["has_episodes"] else None),
         "replace_context_menu": False,
         "replace_context_menu": False,
         "art": {}
         "art": {}
     }
     }
-    """
-    item["art"]["thumb"] = item["thumbnail"]
-    item["art"]["poster"] = item["thumbnail"]
-    item["art"]["fanart"] = fanart_url
-    item["art"]["icon"] = item["thumbnail"]
-    item["art"]["landscape"] = item["thumbnail"]
-    item["art"]["clearlogo"] = item["thumbnail"]
-    """
-
+    set_thumbnail(item)
     return item
     return item
 
 
 
 
@@ -359,12 +413,17 @@ def prepare_movies_to_list(data, prefixed=True):
 
 
 
 
 def show_busy_dialog():
 def show_busy_dialog():
-    xbmc.executebuiltin('ActivateWindow(busydialognocancel)')
+    if KODI_VERSION < 18:
+        xbmc.executebuiltin('ActivateWindow(busydialog)')
+    else:
+        xbmc.executebuiltin('ActivateWindow(busydialognocancel)')
 
 
 
 
 def hide_busy_dialog():
 def hide_busy_dialog():
-    # xbmc.executebuiltin("Dialog.Close(busydialog)")
-    xbmc.executebuiltin('Dialog.Close(busydialognocancel)')
+    if KODI_VERSION < 18:
+        xbmc.executebuiltin("Dialog.Close(busydialog)")
+    else:
+        xbmc.executebuiltin('Dialog.Close(busydialognocancel)')
 
 
 
 
 def logout_kodi():
 def logout_kodi():

+ 11 - 2
startup.py

@@ -1,6 +1,12 @@
 # -*- coding: utf-8 -*-
 # -*- coding: utf-8 -*-
 
 
 import traceback
 import traceback
+import sys
+import os
+
+PACKAGE_PARENT = '..'
+SCRIPT_DIR = os.path.dirname(os.path.realpath(os.path.join(os.getcwd(), os.path.expanduser(__file__))))
+sys.path.append(os.path.normpath(os.path.join(SCRIPT_DIR, PACKAGE_PARENT)))
 
 
 if __name__ == "__main__":
 if __name__ == "__main__":
     output = None
     output = None
@@ -10,9 +16,12 @@ if __name__ == "__main__":
         output = __output
         output = __output
         __run()
         __run()
 
 
-    except Exception as e:
+    except SystemExit:
+        pass
+
+    except:
         import xbmcgui
         import xbmcgui
 
 
         xbmcgui.Dialog().ok("Entschuldigung :(",
         xbmcgui.Dialog().ok("Entschuldigung :(",
                             "Leider wurde ein unerwarteter Fehler festgestellt.\nBitte erneut Probieren ansonsten das Plugin erneut [B]Installieren[/B]!")
                             "Leider wurde ein unerwarteter Fehler festgestellt.\nBitte erneut Probieren ansonsten das Plugin erneut [B]Installieren[/B]!")
-        raise
+        raise

+ 2 - 2
utf8.txt

@@ -10,7 +10,7 @@
 #  | |              | || |              | || |              | || |              | |  | |              | || |              | || |              | || |              | |
 #  | |              | || |              | || |              | || |              | |  | |              | || |              | || |              | || |              | |
 #  | '--------------' || '--------------' || '--------------' || '--------------' |  | '--------------' || '--------------' || '--------------' || '--------------' |
 #  | '--------------' || '--------------' || '--------------' || '--------------' |  | '--------------' || '--------------' || '--------------' || '--------------' |
 #   '----------------'  '----------------'  '----------------'  '----------------'    '----------------'  '----------------'  '----------------'  '----------------' 
 #   '----------------'  '----------------'  '----------------'  '----------------'    '----------------'  '----------------'  '----------------'  '----------------' 
-# Release: %RELEASE%
+# Release: stable
 
 
 
 
 
 
@@ -586,7 +586,7 @@
 
 
 
 
 import sys
 import sys
-if sys.version[0] == '2':
+if sys.version[0] == '2' and hasattr(sys, "setdefaultencoding"):
     reload(sys)
     reload(sys)
     sys.setdefaultencoding("utf-8")
     sys.setdefaultencoding("utf-8")
 
 

+ 1 - 1
utf8_beta.txt

@@ -586,6 +586,6 @@
 
 
 
 
 import sys
 import sys
-if sys.version[0] == '2':
+if sys.version[0] == '2' and hasattr(sys, "setdefaultencoding"):
     reload(sys)
     reload(sys)
     sys.setdefaultencoding("utf-8")
     sys.setdefaultencoding("utf-8")

+ 9 - 1
xbmc.py

@@ -1,7 +1,9 @@
-def log(*args):
+def log(*args, level=None):
     pass
     pass
 
 
 
 
+LOGERROR = None
+
 PLAYLIST_VIDEO = 1
 PLAYLIST_VIDEO = 1
 
 
 
 
@@ -13,3 +15,9 @@ class Player():
 class PlayList():
 class PlayList():
     def clear(self):
     def clear(self):
         pass
         pass
+
+    def __getitem__(self, item):
+        pass
+
+    def add(self, path, item):
+        pass