From 22b5d413fd59237d63ec10220eb5a4f629c505ce Mon Sep 17 00:00:00 2001
From: Matt <mcarlton00@gmail.com>
Date: Tue, 19 May 2020 21:47:19 -0400
Subject: [PATCH 1/3] Add reset password dialog to addon menu

---
 jellyfin_kodi/connect.py                              | 3 ++-
 jellyfin_kodi/entrypoint/default.py                   | 3 +++
 jellyfin_kodi/entrypoint/service.py                   | 4 +++-
 resources/language/resource.language.en_gb/strings.po | 4 ++++
 resources/language/resource.language.en_us/strings.po | 4 ++++
 5 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/jellyfin_kodi/connect.py b/jellyfin_kodi/connect.py
index cc535370..2e95bc2b 100644
--- a/jellyfin_kodi/connect.py
+++ b/jellyfin_kodi/connect.py
@@ -253,8 +253,9 @@ class Connect(object):
         client.set_credentials(get_credentials())
         manager = client.auth
 
+        username = settings('username')
         try:
-            self.login_manual(manager=manager)
+            self.login_manual(user=username, manager=manager)
         except RuntimeError:
             return
 
diff --git a/jellyfin_kodi/entrypoint/default.py b/jellyfin_kodi/entrypoint/default.py
index fac8581f..b21a71e4 100644
--- a/jellyfin_kodi/entrypoint/default.py
+++ b/jellyfin_kodi/entrypoint/default.py
@@ -112,6 +112,8 @@ class Events(object):
             xbmc.executebuiltin('Addon.OpenSettings(plugin.video.jellyfin)')
         elif mode == 'adduser':
             add_user()
+        elif mode == 'updatepassword':
+            event('UpdatePassword')
         elif mode == 'thememedia':
             get_themes()
         elif mode == 'managelibs':
@@ -177,6 +179,7 @@ def listing():
     directory(translate(33134), "plugin://plugin.video.jellyfin/?mode=addserver", False)
     directory(translate(33054), "plugin://plugin.video.jellyfin/?mode=adduser", False)
     directory(translate(5), "plugin://plugin.video.jellyfin/?mode=settings", False)
+    directory(translate(33161), "plugin://plugin.video.jellyfin/?mode=updatepassword", False)
     directory(translate(33058), "plugin://plugin.video.jellyfin/?mode=reset", False)
     directory(translate(33180), "plugin://plugin.video.jellyfin/?mode=restartservice", False)
 
diff --git a/jellyfin_kodi/entrypoint/service.py b/jellyfin_kodi/entrypoint/service.py
index dace0288..8fc8f36e 100644
--- a/jellyfin_kodi/entrypoint/service.py
+++ b/jellyfin_kodi/entrypoint/service.py
@@ -156,7 +156,7 @@ class Service(xbmc.Monitor):
                               'LibraryChanged', 'ServerOnline', 'SyncLibrary', 'RepairLibrary', 'RemoveLibrary',
                               'SyncLibrarySelection', 'RepairLibrarySelection', 'AddServer',
                               'Unauthorized', 'UserConfigurationUpdated', 'ServerRestarting',
-                              'RemoveServer', 'AddLibrarySelection', 'RemoveLibrarySelection'):
+                              'RemoveServer', 'UpdatePassword', 'AddLibrarySelection', 'RemoveLibrarySelection'):
                 return
 
             data = json.loads(data)[0]
@@ -243,6 +243,8 @@ class Service(xbmc.Monitor):
             self.connect.remove_server(data['Id'])
             xbmc.executebuiltin("Container.Refresh")
 
+        elif method == 'UpdatePassword':
+            self.connect.setup_login_manual()
         elif method == 'UserDataChanged' and self.library_thread:
             if data.get('ServerId') or not window('jellyfin_startup.bool'):
                 return
diff --git a/resources/language/resource.language.en_gb/strings.po b/resources/language/resource.language.en_gb/strings.po
index 23b7e37c..c4690526 100644
--- a/resources/language/resource.language.en_gb/strings.po
+++ b/resources/language/resource.language.en_gb/strings.po
@@ -801,6 +801,10 @@ msgctxt "#33160"
 msgid "To avoid errors, please update Jellyfin for Kodi to version: "
 msgstr "To avoid errors, please update Jellyfin for Kodi to version: "
 
+msgctxt "#33161"
+msgid "Update password"
+msgstr "Update password"
+
 msgctxt "#33162"
 msgid "Reset the music library?"
 msgstr "Reset the music library?"
diff --git a/resources/language/resource.language.en_us/strings.po b/resources/language/resource.language.en_us/strings.po
index 95daafd6..bf410eca 100644
--- a/resources/language/resource.language.en_us/strings.po
+++ b/resources/language/resource.language.en_us/strings.po
@@ -801,6 +801,10 @@ msgctxt "#33160"
 msgid "To avoid errors, please update Jellyfin for Kodi to version: "
 msgstr "To avoid errors, please update Jellyfin for Kodi to version: "
 
+msgctxt "#33161"
+msgid "Update password"
+msgstr "Update password"
+
 msgctxt "#33162"
 msgid "Reset the music library?"
 msgstr "Reset the music library?"

From de95d23e5a3ecc8c7571de1e4775dd5762c187b9 Mon Sep 17 00:00:00 2001
From: Matt <mcarlton00@gmail.com>
Date: Fri, 22 May 2020 18:55:21 -0400
Subject: [PATCH 2/3] Catch bad passwords on addon startup

---
 jellyfin_kodi/connect.py                     | 4 ++++
 jellyfin_kodi/jellyfin/api.py                | 6 +++++-
 jellyfin_kodi/jellyfin/connection_manager.py | 6 ++++--
 3 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/jellyfin_kodi/connect.py b/jellyfin_kodi/connect.py
index 2e95bc2b..641d1f5d 100644
--- a/jellyfin_kodi/connect.py
+++ b/jellyfin_kodi/connect.py
@@ -119,6 +119,10 @@ class Connect(object):
                 if 'ExchangeToken' not in state['Servers'][0]:
                     self.login()
 
+            elif state['State'] == CONNECTION_STATE['Unavailable'] and state['Status_Code'] == 401:
+                # If the saved credentials don't work, restart the addon to force the password dialog to open
+                window('jellyfin.restart', clear=True)
+
             elif state['State'] == CONNECTION_STATE['Unavailable']:
                 raise HTTPException('ServerUnreachable', {})
 
diff --git a/jellyfin_kodi/jellyfin/api.py b/jellyfin_kodi/jellyfin/api.py
index 48c8f023..686588b3 100644
--- a/jellyfin_kodi/jellyfin/api.py
+++ b/jellyfin_kodi/jellyfin/api.py
@@ -430,7 +430,11 @@ class API(object):
         headers.update(auth_token_header)
 
         response = self.send_request(server['address'], "system/info", headers=headers)
-        return response.json() if response.status_code == 200 else {}
+
+        if response.status_code == 200:
+            return response.json()
+        else:
+            return response.status_code
 
     def get_public_info(self, server_address):
         response = self.send_request(server_address, "system/info/public")
diff --git a/jellyfin_kodi/jellyfin/connection_manager.py b/jellyfin_kodi/jellyfin/connection_manager.py
index d6e87115..a23ef4f3 100644
--- a/jellyfin_kodi/jellyfin/connection_manager.py
+++ b/jellyfin_kodi/jellyfin/connection_manager.py
@@ -309,7 +309,7 @@ class ConnectionManager(object):
 
         elif verify_authentication and server.get('AccessToken'):
             system_info = self.API.validate_authentication_token(server)
-            if system_info:
+            if system_info and type(system_info) == dict:
 
                 self._update_server_info(server, system_info)
                 self.config.data['auth.user_id'] = server['UserId']
@@ -319,7 +319,9 @@ class ConnectionManager(object):
 
             server['UserId'] = None
             server['AccessToken'] = None
-            return {'State': CONNECTION_STATE['Unavailable']}
+            return {
+                'State': CONNECTION_STATE['Unavailable'],
+                'Status_Code': system_info}
 
         self._update_server_info(server, system_info)
 

From 9c11dbc113e0fd966b8c118af3ac2bf87b058fc1 Mon Sep 17 00:00:00 2001
From: Matt <mcarlton00@gmail.com>
Date: Sun, 24 May 2020 16:26:39 -0400
Subject: [PATCH 3/3] Validate token returns dict no matter what

---
 jellyfin_kodi/jellyfin/api.py                | 2 +-
 jellyfin_kodi/jellyfin/connection_manager.py | 7 +++----
 2 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/jellyfin_kodi/jellyfin/api.py b/jellyfin_kodi/jellyfin/api.py
index 686588b3..cc8b1547 100644
--- a/jellyfin_kodi/jellyfin/api.py
+++ b/jellyfin_kodi/jellyfin/api.py
@@ -434,7 +434,7 @@ class API(object):
         if response.status_code == 200:
             return response.json()
         else:
-            return response.status_code
+            return { 'Status_Code': response.status_code }
 
     def get_public_info(self, server_address):
         response = self.send_request(server_address, "system/info/public")
diff --git a/jellyfin_kodi/jellyfin/connection_manager.py b/jellyfin_kodi/jellyfin/connection_manager.py
index a23ef4f3..f5eb05e5 100644
--- a/jellyfin_kodi/jellyfin/connection_manager.py
+++ b/jellyfin_kodi/jellyfin/connection_manager.py
@@ -309,7 +309,7 @@ class ConnectionManager(object):
 
         elif verify_authentication and server.get('AccessToken'):
             system_info = self.API.validate_authentication_token(server)
-            if system_info and type(system_info) == dict:
+            if 'Status_Code' not in system_info:
 
                 self._update_server_info(server, system_info)
                 self.config.data['auth.user_id'] = server['UserId']
@@ -319,9 +319,8 @@ class ConnectionManager(object):
 
             server['UserId'] = None
             server['AccessToken'] = None
-            return {
-                'State': CONNECTION_STATE['Unavailable'],
-                'Status_Code': system_info}
+            system_info['State'] = CONNECTION_STATE['Unavailable']
+            return system_info
 
         self._update_server_info(server, system_info)