Jelajahi Sumber

Merge branch 'new-playserver'

A 4 tahun lalu
induk
melakukan
3ee95f9d8a
7 mengubah file dengan 156 tambahan dan 79 penghapusan
  1. 1 0
      .gitignore
  2. 5 4
      framework/__init__.py
  3. 1 1
      make_beta.bat
  4. 5 4
      settings_template.xml
  5. 4 6
      src/consts.py
  6. 95 45
      src/playserver.py
  7. 45 19
      src/plugin.py

+ 1 - 0
.gitignore

@@ -1,3 +1,4 @@
 .idea
 output
 tmp*
+resources/settings.xml

+ 5 - 4
framework/__init__.py

@@ -436,6 +436,11 @@ class Plugin(object):
         self._request = self._parse_request()
         items, rule = self._dispatch(self.request.path)
 
+        if hasattr(self, '_unsynced_storages'):
+            for storage in self._unsynced_storages.values():
+                storage.close()
+            del self._unsynced_storages
+
         """
         wasFinished = self._finished
 
@@ -449,10 +454,6 @@ class Plugin(object):
             if self._viewmode > 0:
                 xbmc.executebuiltin("Container.SetViewMode(" + str(self._viewmode) + ")")
 
-        if hasattr(self, '_unsynced_storages'):
-            for storage in self._unsynced_storages.values():
-                storage.close()
-
         if self.handle > 0 and not wasFinished and items != None:
             self.finish()
             xbmcplugin.endOfDirectory(self.handle, succeeded=True, updateListing=rule.update, cacheToDisc=rule.cache)

+ 1 - 1
make_beta.bat

@@ -44,6 +44,6 @@ echo D | xcopy "changelog.txt" /f /y "C:\Users\SevenX\Dropbox\Crynet\Repo/source
 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/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_template.xml" /f /y "DC:\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
 
 rem pause

+ 5 - 4
settings_template.xml

@@ -75,10 +75,11 @@
 
         <setting label=" " type="lsep" visible="eq(-3,true)"/>
         <setting label="Storage leeren" type="action" action='RunPlugin("plugin://plugin.video.cryflix%RELEASE%/clear_storage/")' visible="eq(-4,true)"/>
+        <setting label="Playserver beenden" type="action" action='RunPlugin("plugin://plugin.video.cryflix%RELEASE%/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>
 </settings>

+ 4 - 6
src/consts.py

@@ -48,9 +48,7 @@ def output(message, to_log_file=True):
     global sock
     try:
         if not sock:
-            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-            sock.settimeout(1)
-            sock.connect(("192.168.1.116", 12345))
+            sock = socket.create_connection(("192.168.1.116", 12345), timeout=1)
 
         if sock:
             sock.send("%s\n" % message)
@@ -175,7 +173,6 @@ def get_storage(name):
 
 def load_session():
     internal_storage = get_storage("session")
-
     if not ("user_id" in internal_storage):
         return None, None
 
@@ -185,12 +182,12 @@ def load_session():
 def clear_session():
     global PORTAL_USERID, PORTAL_SESSION
 
-    output("Clear!!!!!")
-
     internal_storage = PLUGIN.get_storage("session")
     if not ("user_id" in internal_storage):
         return None, None
 
+    output("[SESSION] Clearing!!!!!")
+
     del internal_storage["user_id"]
     del internal_storage["session_hash"]
     internal_storage.sync()
@@ -220,6 +217,7 @@ def read_settings():
 
     PORTAL_USERNAME = PLUGIN.get_setting("username")
     PORTAL_PASSWORD = PLUGIN.get_setting("password")
+
     PORTAL_USERID, PORTAL_SESSION = load_session()
 
     API_URL = ""

+ 95 - 45
src/playserver.py

@@ -39,7 +39,8 @@ class __PlayServer__(object):
         self._episode_id = 0
         self._started = False
         self._last_progress = None
-
+        self._exit_requested = False
+        self._running_since = 0
         self._times = {}
         self._player = xbmc.Player()
 
@@ -55,7 +56,7 @@ class __PlayServer__(object):
         self.__play_progress__(__episode_id__)
 
     def __play_progress__(self, __episode_id__):
-        if not __episode_id__:
+        if not __episode_id__ or not (__episode_id__ in self._times):
             return
 
         current = self._times[__episode_id__]
@@ -67,7 +68,8 @@ class __PlayServer__(object):
 
     def __play_end__(self, __episode_id__):
         self._started = False
-        if not __episode_id__:
+
+        if not __episode_id__ or not (__episode_id__ in self._times):
             return
 
         current = self._times[__episode_id__]
@@ -89,7 +91,10 @@ class __PlayServer__(object):
 
             request = __client_socket__.recv(1024)
 
-            matches = re.search(r"^([^\s]+) /([^/]+)(?:/([^/]+))?/ HTTP", request, re.IGNORECASE | re.MULTILINE)
+            if not request:
+                return False
+
+            matches = re.search(r"^([^\s]+) /([^/]+)(?:/([^/]+))?/[^\s]* HTTP", request, re.IGNORECASE | re.MULTILINE)
             if matches:
                 output("[SERVER-" + str(self._port) + "] Request: %s" % str([matches.group(i + 1) for i in xrange(len(matches.groups()))]))
 
@@ -98,14 +103,19 @@ class __PlayServer__(object):
 
                 if method == "HEAD":
                     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("HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream\r\nConnection: close\r\n\r\n")
 
                 else:
                     if command == "exit":
-                        pass
+                        __client_socket__.send("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
+                        output("[SERVER-" + str(self._port) + "] Playserver will be closed")
+                        self._running = False
+                        return True
 
                     elif command == "play":
                         read_settings()
+                        check_settings()
 
                         episode_id = matches.group(3)
 
@@ -119,11 +129,12 @@ class __PlayServer__(object):
                                 raise Exception("Got no episode url")
 
                             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("HTTP/1.1 301 Moved Permanently\r\nLocation: %s\r\nConnection: close\r\n\r\n" % episode_url)
 
                         except Exception as e:
-                            output("[SERVER-" + str(self._port) + "] Client Error: %s" % traceback.format_exc())
-                            __client_socket__.send('HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n')
+                            self._running = False
+                            output("[SERVER-" + str(self._port) + "] Client Play Error: %s" % traceback.format_exc())
+                            __client_socket__.send("HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n")
 
                             PLUGIN.notify("Fehler beim Abspielen!")
 
@@ -140,7 +151,8 @@ class __PlayServer__(object):
 
             return True
 
-        except Exception as e:
+        except:
+            self._running = False
             output("[SERVER-" + str(self._port) + "] Client Error: %s" % traceback.format_exc())
             return False
 
@@ -148,10 +160,6 @@ class __PlayServer__(object):
             __client_socket__.close()
 
     def __cleanup__(self):
-        #ifdef DEBUG
-        PLUGIN.notify("Server %s closed" % self._port)
-        #endif
-
         self._thread = None
         self._running = False
         self._port = None
@@ -204,9 +212,51 @@ class __PlayServer__(object):
         else:
             do_end()
 
+    @staticmethod
+    def __save__(port, created):
+        server_storage = get_storage("server")
+        server_storage["created"] = created
+        server_storage["port"] = port
+        server_storage.sync()
+
     def __callback__(self):
         server = None
         monitor = None
+
+        port = None
+
+        try:
+            server_storage = get_storage("server")
+            if not (server_storage is None or not ("port" in server_storage)):
+                created = int(server_storage["created"])
+                port = int(server_storage["port"])
+
+                if not port or time.time() - created > 60 * 60:
+                    port = None
+                    self.__save__(0, 0)
+
+        except:
+            pass
+
+        if port:
+            try:
+                # Try to reach current running Server
+                if socket.create_connection(("127.0.0.1", port), timeout=5):
+                    self._port = port
+
+                    output("[SERVER-" + str(self._port) + "] Playserver reached at %s" % port)
+
+                    return True
+
+                raise Exception("")
+
+            except:
+                port = None
+                output("[SERVER-" + str(self._port) + "] Playserver not reachable")
+
+        output("[SERVER-" + str(self._port) + "] Need to create Playserver")
+
+        last_file = None
         try:
             server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
             try:
@@ -214,18 +264,6 @@ class __PlayServer__(object):
             except Exception as e:
                 output("[SERVER-" + str(self._port) + "] Startup Error: %s" % traceback.format_exc())
 
-                """
-                try:
-                    # Try to reset current running Server
-                    client = socket.create_connection(("127.0.0.1", 0))
-                    if client:
-                        client.send("GET /reset/ HTTP/1.1\r\n\r\n")
-                        client.close()
-
-                except Exception as e:
-                    PLUGIN.notify("Video konnte nicht abgespielt werden!")
-                """
-
                 return False
 
             # Setup socket
@@ -234,13 +272,6 @@ class __PlayServer__(object):
             except:
                 output("[SERVER-" + str(self._port) + "] Failed to set SO_REUSEADDR: %s" % traceback.format_exc())
 
-            """
-            try:
-                server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
-            except:
-                output("[SERVER-"+str(self._port)+"] Failed to set SO_REUSEPORT: %s" % traceback.format_exc())
-            """
-
             try:
                 server.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
             except:
@@ -251,9 +282,12 @@ class __PlayServer__(object):
             addr = server.getsockname()
             self._running = True
             self._port = addr[1]
+
+            self.__save__(self._port, time.time())
+
             output("[SERVER-" + str(self._port) + "] Started")
-            last_action = time.time()
 
+            failed = 0
             monitor = xbmc.Monitor()
             while True:
                 client_sock = None
@@ -266,9 +300,16 @@ class __PlayServer__(object):
                     pass
                 except Exception as e:
                     output("[SERVER-" + str(self._port) + "] Error: %s" % traceback.format_exc())
+                    failed += 1
+                    if failed > 10:
+                        self.__save__(0, 0)
+                        raise Exception("Too many errors")
+
                     xbmc.sleep(100)
                     continue
 
+                failed = 0
+
                 if client_sock:
                     output("[SERVER-" + str(self._port) + "] Got client! %s" % str(address))
 
@@ -280,7 +321,6 @@ class __PlayServer__(object):
                         client_handler.start()
 
                         output("[SERVER-" + str(self._port) + "] Client thread started!")
-                        last_action = time.time() + 5
 
                     except Exception as e:
                         output("[SERVER-" + str(self._port) + "] Error: %s" % traceback.format_exc())
@@ -290,17 +330,12 @@ class __PlayServer__(object):
                 is_playing = self._player.isPlayingVideo()
                 if is_playing:
                     current_file = self._player.getPlayingFile()
-                    if current_file and ("127.0.0.1:%s" % self._port in current_file):
-                        last_action = time.time()
-
-                diff = time.time() - last_action
 
-                aborted = monitor.abortRequested() > 0
-                output("[SERVER-" + str(self._port) + "] Last action: %s - Abort: %s - %s" % (diff, aborted, current_file))
+                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))
 
-                self.__track__(diff > 10.0 or aborted)
-
-                if diff > 10.0 or aborted:
+                self.__track__(aborted)
+                if aborted:
                     break
 
             return True
@@ -314,6 +349,21 @@ class __PlayServer__(object):
             if server:
                 output("[SERVER-" + str(self._port) + "] Closed")
 
+            is_playing = self._player.isPlayingVideo()
+            current_file = None
+            if is_playing:
+                current_file = self._player.getPlayingFile()
+                if current_file and "127.0.0.1:%s/play/" % self._port in current_file:
+                    output("[SERVER-" + str(self._port) + "] Also stop Player")
+
+                    xbmc.executebuiltin("PlayerControl(stop)")
+
+                else:
+                    current_file = None
+
+            if self._exit_requested or DEBUG:
+                PLUGIN.notify("Playserver wurde beendet")
+
             try:
                 if server:
                     server.close()
@@ -321,7 +371,7 @@ class __PlayServer__(object):
                 pass
 
             monitor = None
-
+            self.__save__(0, 0)
             self.__cleanup__()
 
     @property

+ 45 - 19
src/plugin.py

@@ -5,6 +5,7 @@ from consts import *
 import datetime
 import pprint
 import copy
+import urllib
 
 
 @PLUGIN.route("/empty/", name="empty", update=False, cache=True)
@@ -387,33 +388,28 @@ def play_episode(episode_id=0, ask_playlist=0):
             tried += 1
 
             if tried > 25:
-                raise Exception("Failed to start Playserver")
+                raise Exception("Failed to reach Playserver #1")
 
         play_port = server.__port__
 
         if not play_port:
-            raise Exception("Playserver got no port")
+            raise Exception("Failed to reach Playserver #2")
+
+        output("[PLAY] Using playserver at %s" % play_port)
 
-        output("[PLAY] Server started as %s" % play_port)
         #ifdef DEBUG
         PLUGIN.notify("Playserver at %s" % play_port)
         #endif
 
     except:
         output("[PLAY] Error: %s" % traceback.format_exc())
-
-        #ifdef DEBUG
-        # PLUGIN.notify(repr(e))
-        #endif
+        PLUGIN.notify("Video konnte nicht abgespielt werden!")
 
         raise
 
     # Main Episode
     episode = episode_result["data"]
-    path = "http://127.0.0.1:%s/play/%s/" % (play_port, episode["id"])
-
     li = copy.copy(item)
-    li["path"] = path
     li["properties"] = {
         "MovieID": unicode(episode["id"])
     }
@@ -431,16 +427,14 @@ def play_episode(episode_id=0, ask_playlist=0):
         else:
             li["info"]["tagline"] = tagline
 
+    li["path"] = path = "http://127.0.0.1:%s/play/%s/%s.mkv" % (play_port, episode["id"], urllib.quote(li["label"]))
     li = PLUGIN._listitemify(li).as_xbmc_listitem()
     playlist.add(path, li)
 
     # Playlist episodes
     if "next_episodes" in episode_result["data"]:
         for episode in episode_result["data"]["next_episodes"]:
-            path = "http://127.0.0.1:%s/play/%s/" % (play_port, episode["id"])
-
             li = copy.copy(item)
-            li["path"] = path
             li["properties"] = {
                 "MovieID": unicode(episode["id"])
             }
@@ -458,9 +452,15 @@ def play_episode(episode_id=0, ask_playlist=0):
                 else:
                     li["info"]["tagline"] = tagline
 
+            li["path"] = path = "http://127.0.0.1:%s/play/%s/%s.mkv" % (play_port, episode["id"], urllib.quote(li["label"]))
             li = PLUGIN._listitemify(li).as_xbmc_listitem()
             playlist.add(path, li)
 
+    #ifdef DEBUG
+    for idx in range(playlist.size()):
+        output("[PLAY] %s - Item %s" % (idx, playlist[idx].getPath()))
+    #endif
+
     first = playlist[0]
     if first:
         episode_id = first.getProperty("MovieID")
@@ -635,11 +635,6 @@ def search(is_actor="0"):
     return empty()
 
 
-@PLUGIN.route("/search_result/<is_actor>/<query>/", name="search_result", cache=True, update=False, content_type="movies", view_mode=get_view("thumbnail"))
-def search_result(is_actor="0", query=0):
-    return empty()
-
-
 @PLUGIN.route("/open_settings/", name="open_settings", cache=True)
 def open_settings():
     PLUGIN.open_settings()
@@ -660,6 +655,31 @@ def account_logout():
     return None
 
 
+@PLUGIN.route("/stop_playserver/", name="stop_playserver", cache=False)
+def stop_playserver():
+    server = get_storage("server")
+    if server is None or not ("port" in server) or server["port"] == 0:
+        PLUGIN.notify(u"Playserver läuft nicht!")
+
+    else:
+        try:
+            client = socket.create_connection(("127.0.0.1", server["port"]), timeout=10)
+            if client:
+                client.send("GET /exit/ HTTP/1.1")
+                client.close()
+
+            xbmc.executebuiltin("PlayerControl(stop)")
+
+        except:
+            PLUGIN.notify("Playserver konnte nicht beendet werden!")
+            output("[SERVER] Stop error: %s" % traceback.format_exc())
+
+        finally:
+            __PlayServer__.__save__(0, 0)
+
+    return empty()
+
+
 # Main
 
 
@@ -906,10 +926,16 @@ def main():
 
 
 def __run():
+    output("==================================== START ====================================")
+
     try:
         PLUGIN.run()
-    finally:
+    except:
         hide_busy_dialog()
+        raise
+
+    finally:
+        output("==================================== END ====================================")
 
         try:
             os.chdir(os.path.dirname(os.path.abspath(__file__)))