Initial Kodi context menu commit

This commit is contained in:
tomkat83 2016-10-22 17:15:10 +02:00
parent 38115fb5a9
commit e2776261c3
34 changed files with 2029 additions and 411 deletions

View file

@ -15,6 +15,13 @@
</extension>
<extension point="xbmc.service" library="service.py" start="login">
</extension>
<extension point="kodi.context.item" library="contextmenu.py">
<item>
<label>30401</label>
<description>Settings for the Plex Server</description>
<visible>[!IsEmpty(ListItem.DBID) + !StringCompare(ListItem.DBID,-1) | !IsEmpty(ListItem.Property(plexid))] + !IsEmpty(Window(10000).Property(plex_context))</visible>
</item>
</extension>
<extension point="xbmc.addon.metadata">
<platform>all</platform>
<language>en</language>

View file

@ -1,175 +1,52 @@
# -*- coding: utf-8 -*-
#################################################################################################
###############################################################################
import logging
import os
import sys
import urlparse
import xbmc
import xbmcaddon
import xbmcgui
#################################################################################################
###############################################################################
_addon = xbmcaddon.Addon(id='plugin.video.emby')
_addon_path = _addon.getAddonInfo('path').decode('utf-8')
_base_resource = xbmc.translatePath(os.path.join(_addon_path, 'resources', 'lib')).decode('utf-8')
_addon = xbmcaddon.Addon(id='plugin.video.plexkodiconnect')
try:
_addon_path = _addon.getAddonInfo('path').decode('utf-8')
except TypeError:
_addon_path = _addon.getAddonInfo('path').decode()
try:
_base_resource = xbmc.translatePath(os.path.join(
_addon_path,
'resources',
'lib')).decode('utf-8')
except TypeError:
_base_resource = xbmc.translatePath(os.path.join(
_addon_path,
'resources',
'lib')).decode()
sys.path.append(_base_resource)
#################################################################################################
import api
import artwork
import downloadutils
import librarysync
import read_embyserver as embyserver
import embydb_functions as embydb
import kodidb_functions as kodidb
import musicutils as musicutils
from utils import settings, language as lang, kodiSQL
#################################################################################################
###############################################################################
import loghandler
from context_entry import ContextMenu
###############################################################################
loghandler.config()
log = logging.getLogger("EMBY.contextmenu")
log = logging.getLogger("PLEX.contextmenu")
#################################################################################################
###############################################################################
# Kodi contextmenu item to configure the emby settings
if __name__ == '__main__':
if __name__ == "__main__":
kodiId = xbmc.getInfoLabel('ListItem.DBID').decode('utf-8')
itemType = xbmc.getInfoLabel('ListItem.DBTYPE').decode('utf-8')
itemId = ""
if not itemType:
if xbmc.getCondVisibility("Container.Content(albums)"):
itemType = "album"
elif xbmc.getCondVisibility("Container.Content(artists)"):
itemType = "artist"
elif xbmc.getCondVisibility("Container.Content(songs)"):
itemType = "song"
elif xbmc.getCondVisibility("Container.Content(pictures)"):
itemType = "picture"
else:
log.info("ItemType is unknown.")
if (not kodiId or kodiId == "-1") and xbmc.getInfoLabel("ListItem.Property(embyid)"):
itemId = xbmc.getInfoLabel("ListItem.Property(embyid)")
elif kodiId and itemType:
embyconn = kodiSQL('emby')
embycursor = embyconn.cursor()
emby_db = embydb.Embydb_Functions(embycursor)
item = emby_db.getItem_byKodiId(kodiId, itemType)
embycursor.close()
try:
itemId = item[0]
except TypeError:
pass
log.info("Found ItemId: %s ItemType: %s" % (itemId, itemType))
if itemId:
dialog = xbmcgui.Dialog()
emby = embyserver.Read_EmbyServer()
item = emby.getItem(itemId)
API = api.API(item)
userdata = API.getUserData()
likes = userdata['Likes']
favourite = userdata['Favorite']
options = []
if favourite:
# Remove from emby favourites
options.append(lang(30406))
else:
# Add to emby favourites
options.append(lang(30405))
if itemType == "song":
# Set custom song rating
options.append(lang(30407))
# Refresh item
options.append(lang(30410))
# Delete item
options.append(lang(30409))
# Addon settings
options.append(lang(30408))
# Display select dialog and process results
resp = xbmcgui.Dialog().select(lang(30401), options)
if resp > -1:
selected = options[resp]
if selected == lang(30410):
# Refresh item
emby.refreshItem(itemId)
elif selected == lang(30405):
# Add favourite
emby.updateUserRating(itemId, favourite=True)
elif selected == lang(30406):
# Delete favourite
emby.updateUserRating(itemId, favourite=False)
elif selected == lang(30407):
# Update song rating
kodiconn = kodiSQL('music')
kodicursor = kodiconn.cursor()
query = "SELECT rating FROM song WHERE idSong = ?"
kodicursor.execute(query, (kodiId,))
try:
value = kodicursor.fetchone()[0]
current_value = int(round(float(value),0))
except TypeError:
pass
else:
new_value = dialog.numeric(0, lang(30411), str(current_value))
if new_value > -1:
new_value = int(new_value)
if new_value > 5:
new_value = 5
if settings('enableUpdateSongRating') == "true":
musicutils.updateRatingToFile(new_value, API.getFilePath())
query = "UPDATE song SET rating = ? WHERE idSong = ?"
kodicursor.execute(query, (new_value, kodiId,))
kodiconn.commit()
'''if settings('enableExportSongRating') == "true":
like, favourite, deletelike = musicutils.getEmbyRatingFromKodiRating(new_value)
emby.updateUserRating(itemId, like, favourite, deletelike)'''
finally:
kodicursor.close()
elif selected == lang(30408):
# Open addon settings
xbmc.executebuiltin("Addon.OpenSettings(plugin.video.emby)")
elif selected == lang(30409):
# delete item from the server
delete = True
if settings('skipContextMenu') != "true":
resp = dialog.yesno(
heading=lang(29999),
line1=lang(33041))
if not resp:
log.info("User skipped deletion for: %s." % itemId)
delete = False
if delete:
log.info("Deleting request: %s" % itemId)
emby.deleteItem(itemId)
xbmc.sleep(500)
xbmc.executebuiltin('Container.Refresh')
try:
# Start the context menu
ContextMenu()
except Exception as error:
log.exception(error)
import traceback
log.exception("Traceback:\n%s" % traceback.format_exc())
raise

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<strings>
<!-- Add-on settings -->
<string id="29999">PlexKodiConnect</string>
<string id="30000">Server Address (IP)</string><!-- Verified -->
<string id="30002">Preferred playback method</string><!-- Verified -->
<string id="30004">Log level</string><!-- Verified -->
@ -260,7 +261,11 @@
<string id="30406">Remove from Plex favorites</string>
<string id="30407">Set custom song rating</string>
<string id="30408">Plex addon settings</string>
<string id="30409">Delete item from the server</string>
<string id="30409">Delete item from server</string>
<string id="30410">Refresh this item</string>
<string id="30411">Set custom song rating (0-5)</string>
<string id="30412">Force transcode</string>
<string id="30413">Enable Plex context menu in Kodi</string>
<!-- add-on settings -->
<string id="30500">Verify Host SSL Certificate (more secure)</string>
@ -283,7 +288,7 @@
<string id="30517">[COLOR yellow]Enter network credentials[/COLOR]</string>
<string id="30518">Enable Plex Trailers (Plexpass is needed)</string>
<string id="30519">Ask to play trailers</string>
<string id="30520">Skip Emby delete confirmation for the context menu (use at your own risk)</string>
<string id="30520">Skip Plex delete confirmation for the context menu (use at your own risk)</string>
<string id="30521">Jump back on resume (in seconds)</string>
<string id="30522">Force transcode H265</string>
<string id="30523">Music metadata options (not compatible with direct stream)</string>
@ -344,6 +349,7 @@
<string id="33031">Comparing:</string>
<string id="33032">Failed to generate a new device Id. See your logs for more information.</string>
<string id="33033">Kodi will now restart to apply the changes.</string>
<string id="33041">Delete file(s) from Plex Server? This will also delete the file(s) from disk!</string>
<!-- New to Plex -->
<string id="39000">- Number of trailers to play before a movie</string>

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<strings>
<string id="29999">PlexKodiConnect</string>
<string id="30000">IP-Adresse des Servers</string>
<string id="30001">Automatisches Öffnen von Ordnern mit einem Eintrag</string>
<string id="30002">Gewünschte Wiedergabe-Methode</string>
@ -21,6 +22,7 @@
<string id="30517">Netzwerk Credentials eingeben</string>
<string id="30529">PlexKodiConnect Start Verzögerung (in Sekunden)</string>
<string id="30527">Extras ignorieren, wenn Nächste Episode gespielt wird</string>
<string id="30520">Sicherheitsabfrage bei Löschen des Plex Elements deaktivieren</string>
<string id="30521">Bei Wiederaufnahme zurückspulen (in Sekunden)</string>
<string id="30505">[COLOR yellow]Anzahl Login-Versuche zurücksetzen[/COLOR]</string>
@ -282,7 +284,24 @@
<string id="30311">Musikstücke</string>
<string id="30312">Kanäle</string>
<!-- contextmenu -->
<string id="30401">Plex Optionen</string>
<string id="30402">Clear like for this item</string>
<string id="30403">Like this item</string>
<string id="30404">Dislike this item</string>
<string id="30405">Add to Plex favorites</string>
<string id="30406">Remove from Plex favorites</string>
<string id="30407">Set custom song rating</string>
<string id="30408">Plex Addon Optionen</string>
<string id="30409">Element in Plex Server löschen</string>
<string id="30410">Element neu laden</string>
<string id="30411">Set custom song rating (0-5)</string>
<string id="30412">Transkodieren erzwingen</string>
<string id="30413">Plex Kontextmenu in Kodi aktivieren</string>
<string id="33033">Kodi wird jetzt neu gestartet um die Änderungen anzuwenden.</string>
<string id="33041">Eintrag vom Plex Server löschen? Dies wird die Dateien auch endgültig von der Festplatte löschen!</string>
<!-- New to Plex -->
<string id="39000">- Anzahl abzuspielender Trailer vor einem Film</string>

View file

@ -526,3 +526,22 @@ def scrobble(ratingKey, state):
return
downloadutils.DownloadUtils().downloadUrl(url)
log.info("Toggled watched state for Plex item %s" % ratingKey)
def delete_item_from_pms(plexid):
"""
Deletes the item plexid from the Plex Media Server (and the harddrive!).
Do make sure that the currently logged in user has the credentials
Returns True if successful, False otherwise
"""
xml = downloadutils.DownloadUtils().downloadUrl(
'{server}/library/metadata/%s' % plexid,
action_type="DELETE")
try:
xml.attrib
except AttributeError:
log.error('Could not delete Plex id %s' % plexid)
return False
log.info(xml.dump)
return True

View file

@ -0,0 +1,194 @@
# -*- coding: utf-8 -*-
###############################################################################
import logging
import xbmc
import xbmcaddon
import PlexAPI
from PlexFunctions import GetPlexMetadata, delete_item_from_pms
import embydb_functions as embydb
from utils import settings, dialog, language as lang, kodiSQL
from dialogs import context
###############################################################################
log = logging.getLogger("PLEX."+__name__)
addonName = 'PlexKodiConnect'
OPTIONS = {
'Refresh': lang(30410),
'Delete': lang(30409),
'Addon': lang(30408),
# 'AddFav': lang(30405),
# 'RemoveFav': lang(30406),
# 'RateSong': lang(30407),
'Transcode': lang(30412)
}
###############################################################################
class ContextMenu(object):
_selected_option = None
def __init__(self):
self.kodi_id = xbmc.getInfoLabel('ListItem.DBID').decode('utf-8')
self.item_type = self._get_item_type()
self.item_id = self._get_item_id(self.kodi_id, self.item_type)
log.info("Found item_id: %s item_type: %s"
% (self.item_id, self.item_type))
if not self.item_id:
return
self.item = GetPlexMetadata(self.item_id)
self.api = PlexAPI.API(self.item)
if self._select_menu():
self._action_menu()
if self._selected_option in (OPTIONS['Delete'],
OPTIONS['Refresh']):
log.info("refreshing container")
xbmc.sleep(500)
xbmc.executebuiltin('Container.Refresh')
@classmethod
def _get_item_type(cls):
item_type = xbmc.getInfoLabel('ListItem.DBTYPE').decode('utf-8')
if not item_type:
if xbmc.getCondVisibility('Container.Content(albums)'):
item_type = "album"
elif xbmc.getCondVisibility('Container.Content(artists)'):
item_type = "artist"
elif xbmc.getCondVisibility('Container.Content(songs)'):
item_type = "song"
elif xbmc.getCondVisibility('Container.Content(pictures)'):
item_type = "picture"
else:
log.info("item_type is unknown")
return item_type
@classmethod
def _get_item_id(cls, kodi_id, item_type):
item_id = xbmc.getInfoLabel('ListItem.Property(plexid)')
if not item_id and kodi_id and item_type:
with embydb.GetEmbyDB() as emby_db:
item = emby_db.getItem_byKodiId(kodi_id, item_type)
try:
item_id = item[0]
except TypeError:
log.error('Could not get the Plex id for context menu')
return item_id
def _select_menu(self):
# Display select dialog
options = []
if self.item_type in ("movie", "episode", "song"):
options.append(OPTIONS['Transcode'])
# userdata = self.api.getUserData()
# if userdata['Favorite']:
# # Remove from emby favourites
# options.append(OPTIONS['RemoveFav'])
# else:
# # Add to emby favourites
# options.append(OPTIONS['AddFav'])
# if self.item_type == "song":
# # Set custom song rating
# options.append(OPTIONS['RateSong'])
# Refresh item
options.append(OPTIONS['Refresh'])
# Delete item, only if the Plex Home main user is logged in
if settings('plex_restricteduser') != 'true':
options.append(OPTIONS['Delete'])
# Addon settings
options.append(OPTIONS['Addon'])
addon = xbmcaddon.Addon('plugin.video.plexkodiconnect')
context_menu = context.ContextMenu("script-emby-context.xml",
addon.getAddonInfo('path'),
"default", "1080i")
context_menu.set_options(options)
context_menu.doModal()
if context_menu.is_selected():
self._selected_option = context_menu.get_selected()
return self._selected_option
def _action_menu(self):
selected = self._selected_option
if selected == OPTIONS['Transcode']:
pass
elif selected == OPTIONS['Refresh']:
self.emby.refreshItem(self.item_id)
# elif selected == OPTIONS['AddFav']:
# self.emby.updateUserRating(self.item_id, favourite=True)
# elif selected == OPTIONS['RemoveFav']:
# self.emby.updateUserRating(self.item_id, favourite=False)
# elif selected == OPTIONS['RateSong']:
# self._rate_song()
elif selected == OPTIONS['Addon']:
xbmc.executebuiltin('Addon.OpenSettings(plugin.video.plexkodiconnect)')
elif selected == OPTIONS['Delete']:
self._delete_item()
def _rate_song(self):
conn = kodiSQL('music')
cursor = conn.cursor()
query = "SELECT rating FROM song WHERE idSong = ?"
cursor.execute(query, (self.kodi_id,))
try:
value = cursor.fetchone()[0]
current_value = int(round(float(value), 0))
except TypeError:
pass
else:
new_value = dialog("numeric", 0, lang(30411), str(current_value))
if new_value > -1:
new_value = int(new_value)
if new_value > 5:
new_value = 5
if settings('enableUpdateSongRating') == "true":
musicutils.updateRatingToFile(new_value, self.api.get_file_path())
query = "UPDATE song SET rating = ? WHERE idSong = ?"
cursor.execute(query, (new_value, self.kodi_id,))
conn.commit()
finally:
cursor.close()
def _delete_item(self):
delete = True
if settings('skipContextMenu') != "true":
if not dialog(type_="yesno", heading=addonName, line1=lang(33041)):
log.info("User skipped deletion for: %s", self.item_id)
delete = False
if delete:
log.info("Deleting Plex item with id %s", self.item_id)
delete_item_from_pms(self.item_id)

View file

@ -1 +0,0 @@
# Dummy file to make this directory a package.

View file

@ -1,76 +0,0 @@
# -*- coding: utf-8 -*-
##################################################################################################
import os
import xbmcgui
import xbmcaddon
##################################################################################################
addon = xbmcaddon.Addon('plugin.video.plexkodiconnect')
ACTION_BACK = 92
SIGN_IN = 200
REMIND_LATER = 201
class LoginConnect(xbmcgui.WindowXMLDialog):
def __init__(self, *args, **kwargs):
xbmcgui.WindowXMLDialog.__init__(self, *args, **kwargs)
def __add_editcontrol(self, x, y, height, width, password=0):
media = os.path.join(addon.getAddonInfo('path'), 'resources', 'skins', 'default', 'media')
control = xbmcgui.ControlEdit(0,0,0,0,
label="User",
font="font10",
textColor="ff464646",
focusTexture=os.path.join(media, "button-focus.png"),
noFocusTexture=os.path.join(media, "button-focus.png"),
isPassword=password)
control.setPosition(x,y)
control.setHeight(height)
control.setWidth(width)
self.addControl(control)
return control
def onInit(self):
self.user_field = self.__add_editcontrol(685,385,40,500)
self.setFocus(self.user_field)
self.password_field = self.__add_editcontrol(685,470,40,500, password=1)
self.signin_button = self.getControl(SIGN_IN)
self.remind_button = self.getControl(REMIND_LATER)
self.user_field.controlUp(self.remind_button)
self.user_field.controlDown(self.password_field)
self.password_field.controlUp(self.user_field)
self.password_field.controlDown(self.signin_button)
self.signin_button.controlUp(self.password_field)
self.remind_button.controlDown(self.user_field)
def onClick(self, control):
if control == SIGN_IN:
# Sign in to emby connect
self.user = self.user_field.getText()
__password = self.password_field.getText()
### REVIEW ONCE CONNECT MODULE IS MADE
self.close()
elif control == REMIND_LATER:
# Remind me later
self.close()
def onAction(self, action):
if action == ACTION_BACK:
self.close()

View file

@ -0,0 +1,6 @@
# Dummy file to make this directory a package.
# from serverconnect import ServerConnect
# from usersconnect import UsersConnect
# from loginconnect import LoginConnect
# from loginmanual import LoginManual
# from servermanual import ServerManual

View file

@ -0,0 +1,93 @@
# -*- coding: utf-8 -*-
###############################################################################
import logging
import os
import xbmcgui
import xbmcaddon
from utils import window
###############################################################################
log = logging.getLogger("PLEX."+__name__)
addon = xbmcaddon.Addon('plugin.video.plexkodiconnect')
ACTION_PARENT_DIR = 9
ACTION_PREVIOUS_MENU = 10
ACTION_BACK = 92
ACTION_SELECT_ITEM = 7
ACTION_MOUSE_LEFT_CLICK = 100
LIST = 155
USER_IMAGE = 150
###############################################################################
class ContextMenu(xbmcgui.WindowXMLDialog):
_options = []
selected_option = None
def __init__(self, *args, **kwargs):
xbmcgui.WindowXMLDialog.__init__(self, *args, **kwargs)
def set_options(self, options=[]):
self._options = options
def is_selected(self):
return True if self.selected_option else False
def get_selected(self):
return self.selected_option
def onInit(self):
if window('PlexUserImage'):
self.getControl(USER_IMAGE).setImage(window('PlexUserImage'))
height = 479 + (len(self._options) * 55)
log.info("options: %s", self._options)
self.list_ = self.getControl(LIST)
for option in self._options:
self.list_.addItem(self._add_listitem(option))
self.background = self._add_editcontrol(730, height, 30, 450)
self.setFocus(self.list_)
def onAction(self, action):
if action in (ACTION_BACK, ACTION_PARENT_DIR, ACTION_PREVIOUS_MENU):
self.close()
if action in (ACTION_SELECT_ITEM, ACTION_MOUSE_LEFT_CLICK):
if self.getFocusId() == LIST:
option = self.list_.getSelectedItem()
self.selected_option = option.getLabel()
log.info('option selected: %s', self.selected_option)
self.close()
def _add_editcontrol(self, x, y, height, width, password=0):
media = os.path.join(addon.getAddonInfo('path'), 'resources', 'skins', 'default', 'media')
control = xbmcgui.ControlImage(0, 0, 0, 0,
filename=os.path.join(media, "white.png"),
aspectRatio=0,
colorDiffuse="ff111111")
control.setPosition(x, y)
control.setHeight(height)
control.setWidth(width)
self.addControl(control)
return control
@classmethod
def _add_listitem(cls, label):
return xbmcgui.ListItem(label)

View file

@ -0,0 +1,136 @@
# -*- coding: utf-8 -*-
##################################################################################################
import logging
import os
import xbmcgui
import xbmcaddon
from utils import language as lang
##################################################################################################
log = logging.getLogger("EMBY."+__name__)
addon = xbmcaddon.Addon('plugin.video.emby')
ACTION_PARENT_DIR = 9
ACTION_PREVIOUS_MENU = 10
ACTION_BACK = 92
SIGN_IN = 200
CANCEL = 201
ERROR_TOGGLE = 202
ERROR_MSG = 203
ERROR = {
'Invalid': 1,
'Empty': 2
}
##################################################################################################
class LoginConnect(xbmcgui.WindowXMLDialog):
_user = None
error = None
def __init__(self, *args, **kwargs):
xbmcgui.WindowXMLDialog.__init__(self, *args, **kwargs)
def set_connect_manager(self, connect_manager):
self.connect_manager = connect_manager
def is_logged_in(self):
return True if self._user else False
def get_user(self):
return self._user
def onInit(self):
self.user_field = self._add_editcontrol(725, 385, 40, 500)
self.setFocus(self.user_field)
self.password_field = self._add_editcontrol(725, 470, 40, 500, password=1)
self.signin_button = self.getControl(SIGN_IN)
self.remind_button = self.getControl(CANCEL)
self.error_toggle = self.getControl(ERROR_TOGGLE)
self.error_msg = self.getControl(ERROR_MSG)
self.user_field.controlUp(self.remind_button)
self.user_field.controlDown(self.password_field)
self.password_field.controlUp(self.user_field)
self.password_field.controlDown(self.signin_button)
self.signin_button.controlUp(self.password_field)
self.remind_button.controlDown(self.user_field)
def onClick(self, control):
if control == SIGN_IN:
# Sign in to emby connect
self._disable_error()
user = self.user_field.getText()
password = self.password_field.getText()
if not user or not password:
# Display error
self._error(ERROR['Empty'], lang(30608))
log.error("Username or password cannot be null")
elif self._login(user, password):
self.close()
elif control == CANCEL:
# Remind me later
self.close()
def onAction(self, action):
if (self.error == ERROR['Empty']
and self.user_field.getText() and self.password_field.getText()):
self._disable_error()
if action in (ACTION_BACK, ACTION_PARENT_DIR, ACTION_PREVIOUS_MENU):
self.close()
def _add_editcontrol(self, x, y, height, width, password=0):
media = os.path.join(addon.getAddonInfo('path'), 'resources', 'skins', 'default', 'media')
control = xbmcgui.ControlEdit(0, 0, 0, 0,
label="User",
font="font10",
textColor="ff525252",
focusTexture=os.path.join(media, "button-focus.png"),
noFocusTexture=os.path.join(media, "button-focus.png"),
isPassword=password)
control.setPosition(x, y)
control.setHeight(height)
control.setWidth(width)
self.addControl(control)
return control
def _login(self, username, password):
result = self.connect_manager.loginToConnect(username, password)
if result is False:
self._error(ERROR['Invalid'], lang(33009))
return False
else:
self._user = result
return True
def _error(self, state, message):
self.error = state
self.error_msg.setLabel(message)
self.error_toggle.setVisibleCondition('True')
def _disable_error(self):
self.error = None
self.error_toggle.setVisibleCondition('False')

View file

@ -0,0 +1,145 @@
# -*- coding: utf-8 -*-
##################################################################################################
import logging
import os
import xbmcgui
import xbmcaddon
import read_embyserver as embyserver
from utils import language as lang
##################################################################################################
log = logging.getLogger("EMBY."+__name__)
addon = xbmcaddon.Addon('plugin.video.emby')
ACTION_PARENT_DIR = 9
ACTION_PREVIOUS_MENU = 10
ACTION_BACK = 92
SIGN_IN = 200
CANCEL = 201
ERROR_TOGGLE = 202
ERROR_MSG = 203
ERROR = {
'Invalid': 1,
'Empty': 2
}
##################################################################################################
class LoginManual(xbmcgui.WindowXMLDialog):
_user = None
error = None
username = None
def __init__(self, *args, **kwargs):
self.emby = embyserver.Read_EmbyServer()
xbmcgui.WindowXMLDialog.__init__(self, *args, **kwargs)
def is_logged_in(self):
return True if self._user else False
def set_server(self, server):
self.server = server
def set_user(self, user):
self.username = user or {}
def get_user(self):
return self._user
def onInit(self):
self.signin_button = self.getControl(SIGN_IN)
self.cancel_button = self.getControl(CANCEL)
self.error_toggle = self.getControl(ERROR_TOGGLE)
self.error_msg = self.getControl(ERROR_MSG)
self.user_field = self._add_editcontrol(725, 400, 40, 500)
self.password_field = self._add_editcontrol(725, 475, 40, 500, password=1)
if self.username:
self.user_field.setText(self.username)
self.setFocus(self.password_field)
else:
self.setFocus(self.user_field)
self.user_field.controlUp(self.cancel_button)
self.user_field.controlDown(self.password_field)
self.password_field.controlUp(self.user_field)
self.password_field.controlDown(self.signin_button)
self.signin_button.controlUp(self.password_field)
self.cancel_button.controlDown(self.user_field)
def onClick(self, control):
if control == SIGN_IN:
# Sign in to emby connect
self._disable_error()
user = self.user_field.getText()
password = self.password_field.getText()
if not user:
# Display error
self._error(ERROR['Empty'], lang(30613))
log.error("Username cannot be null")
elif self._login(user, password):
self.close()
elif control == CANCEL:
# Remind me later
self.close()
def onAction(self, action):
if self.error == ERROR['Empty'] and self.user_field.getText():
self._disable_error()
if action in (ACTION_BACK, ACTION_PARENT_DIR, ACTION_PREVIOUS_MENU):
self.close()
def _add_editcontrol(self, x, y, height, width, password=0):
media = os.path.join(addon.getAddonInfo('path'), 'resources', 'skins', 'default', 'media')
control = xbmcgui.ControlEdit(0, 0, 0, 0,
label="User",
font="font10",
textColor="ff525252",
focusTexture=os.path.join(media, "button-focus.png"),
noFocusTexture=os.path.join(media, "button-focus.png"),
isPassword=password)
control.setPosition(x, y)
control.setHeight(height)
control.setWidth(width)
self.addControl(control)
return control
def _login(self, username, password):
result = self.emby.loginUser(self.server, username, password)
if not result:
self._error(ERROR['Invalid'], lang(33009))
return False
else:
self._user = result
return True
def _error(self, state, message):
self.error = state
self.error_msg.setLabel(message)
self.error_toggle.setVisibleCondition('True')
def _disable_error(self):
self.error = None
self.error_toggle.setVisibleCondition('False')

View file

@ -0,0 +1,145 @@
# -*- coding: utf-8 -*-
##################################################################################################
import logging
import xbmc
import xbmcgui
import connect.connectionmanager as connectionmanager
from utils import language as lang
##################################################################################################
log = logging.getLogger("EMBY."+__name__)
CONN_STATE = connectionmanager.ConnectionState
ACTION_PARENT_DIR = 9
ACTION_PREVIOUS_MENU = 10
ACTION_BACK = 92
ACTION_SELECT_ITEM = 7
ACTION_MOUSE_LEFT_CLICK = 100
USER_IMAGE = 150
USER_NAME = 151
LIST = 155
CANCEL = 201
MESSAGE_BOX = 202
MESSAGE = 203
BUSY = 204
EMBY_CONNECT = 205
MANUAL_SERVER = 206
##################################################################################################
class ServerConnect(xbmcgui.WindowXMLDialog):
username = ""
user_image = None
servers = []
_selected_server = None
_connect_login = False
_manual_server = False
def __init__(self, *args, **kwargs):
xbmcgui.WindowXMLDialog.__init__(self, *args, **kwargs)
def set_args(self, **kwargs):
# connect_manager, username, user_image, servers, emby_connect
for key, value in kwargs.iteritems():
setattr(self, key, value)
def is_server_selected(self):
return True if self._selected_server else False
def get_server(self):
return self._selected_server
def is_connect_login(self):
return self._connect_login
def is_manual_server(self):
return self._manual_server
def onInit(self):
self.message = self.getControl(MESSAGE)
self.message_box = self.getControl(MESSAGE_BOX)
self.busy = self.getControl(BUSY)
self.list_ = self.getControl(LIST)
for server in self.servers:
server_type = "wifi" if server.get('ExchangeToken') else "network"
self.list_.addItem(self._add_listitem(server['Name'], server['Id'], server_type))
self.getControl(USER_NAME).setLabel("%s %s" % (lang(33000), self.username.decode('utf-8')))
if self.user_image is not None:
self.getControl(USER_IMAGE).setImage(self.user_image)
if not self.emby_connect: # Change connect user
self.getControl(EMBY_CONNECT).setLabel("[UPPERCASE][B]"+lang(30618)+"[/B][/UPPERCASE]")
if self.servers:
self.setFocus(self.list_)
@classmethod
def _add_listitem(cls, label, server_id, server_type):
item = xbmcgui.ListItem(label)
item.setProperty('id', server_id)
item.setProperty('server_type', server_type)
return item
def onAction(self, action):
if action in (ACTION_BACK, ACTION_PREVIOUS_MENU, ACTION_PARENT_DIR):
self.close()
if action in (ACTION_SELECT_ITEM, ACTION_MOUSE_LEFT_CLICK):
if self.getFocusId() == LIST:
server = self.list_.getSelectedItem()
selected_id = server.getProperty('id')
log.info('Server Id selected: %s', selected_id)
if self._connect_server(selected_id):
self.message_box.setVisibleCondition('False')
self.close()
def onClick(self, control):
if control == EMBY_CONNECT:
self.connect_manager.clearData()
self._connect_login = True
self.close()
elif control == MANUAL_SERVER:
self._manual_server = True
self.close()
elif control == CANCEL:
self.close()
def _connect_server(self, server_id):
server = self.connect_manager.getServerInfo(server_id)
self.message.setLabel("%s %s..." % (lang(30610), server['Name']))
self.message_box.setVisibleCondition('True')
self.busy.setVisibleCondition('True')
result = self.connect_manager.connectToServer(server)
if result['State'] == CONN_STATE['Unavailable']:
self.busy.setVisibleCondition('False')
self.message.setLabel(lang(30609))
return False
else:
xbmc.sleep(1000)
self._selected_server = result['Servers'][0]
return True

View file

@ -0,0 +1,145 @@
# -*- coding: utf-8 -*-
##################################################################################################
import logging
import os
import xbmcgui
import xbmcaddon
import connect.connectionmanager as connectionmanager
from utils import language as lang
##################################################################################################
log = logging.getLogger("EMBY."+__name__)
addon = xbmcaddon.Addon('plugin.video.emby')
CONN_STATE = connectionmanager.ConnectionState
ACTION_PARENT_DIR = 9
ACTION_PREVIOUS_MENU = 10
ACTION_BACK = 92
CONNECT = 200
CANCEL = 201
ERROR_TOGGLE = 202
ERROR_MSG = 203
ERROR = {
'Invalid': 1,
'Empty': 2
}
##################################################################################################
class ServerManual(xbmcgui.WindowXMLDialog):
_server = None
error = None
def __init__(self, *args, **kwargs):
xbmcgui.WindowXMLDialog.__init__(self, *args, **kwargs)
def set_connect_manager(self, connect_manager):
self.connect_manager = connect_manager
def is_connected(self):
return True if self._server else False
def get_server(self):
return self._server
def onInit(self):
self.connect_button = self.getControl(CONNECT)
self.cancel_button = self.getControl(CANCEL)
self.error_toggle = self.getControl(ERROR_TOGGLE)
self.error_msg = self.getControl(ERROR_MSG)
self.host_field = self._add_editcontrol(725, 400, 40, 500)
self.port_field = self._add_editcontrol(725, 525, 40, 500)
self.port_field.setText('8096')
self.setFocus(self.host_field)
self.host_field.controlUp(self.cancel_button)
self.host_field.controlDown(self.port_field)
self.port_field.controlUp(self.host_field)
self.port_field.controlDown(self.connect_button)
self.connect_button.controlUp(self.port_field)
self.cancel_button.controlDown(self.host_field)
def onClick(self, control):
if control == CONNECT:
# Sign in to emby connect
self._disable_error()
server = self.host_field.getText()
port = self.port_field.getText()
if not server or not port:
# Display error
self._error(ERROR['Empty'], lang(30617))
log.error("Server or port cannot be null")
elif self._connect_to_server(server, port):
self.close()
elif control == CANCEL:
# Remind me later
self.close()
def onAction(self, action):
if self.error == ERROR['Empty'] and self.host_field.getText() and self.port_field.getText():
self._disable_error()
if action in (ACTION_BACK, ACTION_PARENT_DIR, ACTION_PREVIOUS_MENU):
self.close()
def _add_editcontrol(self, x, y, height, width):
media = os.path.join(addon.getAddonInfo('path'), 'resources', 'skins', 'default', 'media')
control = xbmcgui.ControlEdit(0, 0, 0, 0,
label="User",
font="font10",
textColor="ffc2c2c2",
focusTexture=os.path.join(media, "button-focus.png"),
noFocusTexture=os.path.join(media, "button-focus.png"))
control.setPosition(x, y)
control.setHeight(height)
control.setWidth(width)
self.addControl(control)
return control
def _connect_to_server(self, server, port):
server_address = "%s:%s" % (server, port)
self._message("%s %s..." % (lang(30610), server_address))
result = self.connect_manager.connectToAddress(server_address)
if result['State'] == CONN_STATE['Unavailable']:
self._message(lang(30609))
return False
else:
self._server = result['Servers'][0]
return True
def _message(self, message):
self.error_msg.setLabel(message)
self.error_toggle.setVisibleCondition('True')
def _error(self, state, message):
self.error = state
self.error_msg.setLabel(message)
self.error_toggle.setVisibleCondition('True')
def _disable_error(self):
self.error = None
self.error_toggle.setVisibleCondition('False')

View file

@ -0,0 +1,104 @@
# -*- coding: utf-8 -*-
##################################################################################################
import logging
import xbmc
import xbmcgui
##################################################################################################
log = logging.getLogger("EMBY."+__name__)
ACTION_PARENT_DIR = 9
ACTION_PREVIOUS_MENU = 10
ACTION_BACK = 92
ACTION_SELECT_ITEM = 7
ACTION_MOUSE_LEFT_CLICK = 100
LIST = 155
MANUAL = 200
CANCEL = 201
##################################################################################################
class UsersConnect(xbmcgui.WindowXMLDialog):
_user = None
_manual_login = False
def __init__(self, *args, **kwargs):
self.kodi_version = int(xbmc.getInfoLabel('System.BuildVersion')[:2])
xbmcgui.WindowXMLDialog.__init__(self, *args, **kwargs)
def set_server(self, server):
self.server = server
def set_users(self, users):
self.users = users
def is_user_selected(self):
return True if self._user else False
def get_user(self):
return self._user
def is_manual_login(self):
return self._manual_login
def onInit(self):
self.list_ = self.getControl(LIST)
for user in self.users:
user_image = ("userflyoutdefault2.png" if 'PrimaryImageTag' not in user
else self._get_user_artwork(user['Id'], 'Primary'))
self.list_.addItem(self._add_listitem(user['Name'], user['Id'], user_image))
self.setFocus(self.list_)
def _add_listitem(self, label, user_id, user_image):
item = xbmcgui.ListItem(label)
item.setProperty('id', user_id)
if self.kodi_version > 15:
item.setArt({'Icon': user_image})
else:
item.setIconImage(user_image)
return item
def onAction(self, action):
if action in (ACTION_BACK, ACTION_PREVIOUS_MENU, ACTION_PARENT_DIR):
self.close()
if action in (ACTION_SELECT_ITEM, ACTION_MOUSE_LEFT_CLICK):
if self.getFocusId() == LIST:
user = self.list_.getSelectedItem()
selected_id = user.getProperty('id')
log.info('User Id selected: %s', selected_id)
for user in self.users:
if user['Id'] == selected_id:
self._user = user
break
self.close()
def onClick(self, control):
if control == MANUAL:
self._manual_login = True
self.close()
elif control == CANCEL:
self.close()
def _get_user_artwork(self, user_id, item_type):
# Load user information set by UserClient
return "%s/emby/Users/%s/Images/%s?Format=original" % (self.server, user_id, item_type)

View file

@ -42,28 +42,18 @@ class KodiMonitor(xbmc.Monitor):
window('plex_kodiScan', clear=True)
def onSettingsChanged(self):
# Monitor emby settings
# Review reset setting at a later time, need to be adjusted to account for initial setup
# changes.
'''currentPath = settings('useDirectPaths')
if window('plex_pluginpath') != currentPath:
# Plugin path value changed. Offer to reset
log.info("Changed to playback mode detected")
window('plex_pluginpath', value=currentPath)
resp = xbmcgui.Dialog().yesno(
heading="Playback mode change detected",
line1=(
"Detected the playback mode has changed. The database "
"needs to be recreated for the change to be applied. "
"Proceed?"))
if resp:
utils.reset()'''
"""
Monitor the PKC settings for changes made by the user
"""
currentLog = settings('logLevel')
if window('plex_logLevel') != currentLog:
# The log level changed, set new prop
log.debug("New log level: %s" % currentLog)
window('plex_logLevel', value=currentLog)
current_context = "true" if settings('enableContext') == "true" else ""
if window('plex_context') != current_context:
log.info("New context setting: %s", current_context)
window('plex_context', value=current_context)
@CatchExceptions(warnuser=False)
def onNotification(self, sender, method, data):

View file

@ -73,6 +73,29 @@ def language(stringid):
return ADDON.getLocalizedString(stringid)
def dialog(type_, *args, **kwargs):
d = xbmcgui.Dialog()
if "icon" in kwargs:
kwargs['icon'] = kwargs['icon'].replace(
"{plex}",
"special://home/addons/plugin.video.plexkodiconnect/icon.png")
if "heading" in kwargs:
kwargs['heading'] = kwargs['heading'].replace("{plex}",
language(29999))
types = {
'yesno': d.yesno,
'ok': d.ok,
'notification': d.notification,
'input': d.input,
'select': d.select,
'numeric': d.numeric
}
return types[type_](*args, **kwargs)
def tryEncode(uniString, encoding='utf-8'):
"""
Will try to encode uniString (in unicode) to encoding. This possibly

View file

@ -38,6 +38,8 @@
<setting id="companionPort" label="39005" type="number" default="3005" option="int" visible="eq(-3,true)"/>
<setting id="plex_restricteduser" type="bool" default="false" visible="false"/>
<setting id="enableContext" type="bool" label="30410" default="true" />
<setting id="skipContextMenu" type="bool" label="30520" default="false" visible="eq(-1,true)" subsetting="true" />
</category>
<category label="30506"><!-- Sync Options -->
@ -117,7 +119,6 @@
<!--
<category label="30235" visible="false">
<setting id="enableCoverArt" type="bool" label="30157" default="true" visible="false"/>
<setting id="skipContextMenu" type="bool" label="30520" default="false" visible="false"/>
<setting id="additionalUsers" type="text" label="30528" default="" visible="false"/>
<setting type="lsep" label="30534" visible="false" />
<setting id="restartMsg" type="bool" label="30530" default="false" visible="false" />

View file

@ -0,0 +1,145 @@
<?xml version="1.0" encoding="UTF-8"?>
<window>
<defaultcontrol always="true">200</defaultcontrol>
<zorder>0</zorder>
<include>dialogeffect</include>
<controls>
<control type="image">
<description>Background fade</description>
<width>100%</width>
<height>100%</height>
<texture>emby-bg-fade.png</texture>
</control>
<control type="group">
<width>600</width>
<left>35%</left>
<top>20%</top>
<control type="image">
<description>Background box</description>
<texture colordiffuse="ff111111">white.png</texture>
<width>600</width>
<height>480</height>
</control>
<control type="group" id="202">
<top>485</top>
<visible>False</visible>
<control type="image">
<description>Error box</description>
<texture colordiffuse="ff222222">white.png</texture>
<width>100%</width>
<height>50</height>
</control>
<control type="label" id="203">
<description>Error message</description>
<textcolor>white</textcolor>
<font>font10</font>
<aligny>center</aligny>
<align>center</align>
<height>50</height>
</control>
</control>
<control type="image">
<description>Emby logo</description>
<texture>logo-white.png</texture>
<aspectratio>keep</aspectratio>
<width>120</width>
<height>49</height>
<top>30</top>
<left>25</left>
</control>
<control type="group">
<width>500</width>
<left>50</left>
<control type="label">
<description>Please sign in</description>
<label>$ADDON[plugin.video.emby 30612]</label>
<textcolor>white</textcolor>
<font>font12</font>
<aligny>top</aligny>
<align>center</align>
<width>100%</width>
<top>100</top>
</control>
<control type="group">
<top>150</top>
<control type="label">
<description>Username</description>
<label>$ADDON[plugin.video.emby 30024]</label>
<textcolor>ffa6a6a6</textcolor>
<font>font10</font>
<aligny>top</aligny>
</control>
<control type="image">
<description>separator</description>
<width>102%</width>
<height>0.5</height>
<top>66</top>
<left>-10</left>
<texture colordiffuse="ff525252" border="90,3,90,3">emby-separator.png</texture>
</control>
</control>
<control type="group">
<description>Password</description>
<top>225</top>
<control type="label">
<description>Password label</description>
<label>$ADDON[plugin.video.emby 30602]</label>
<textcolor>ffa6a6a6</textcolor>
<font>font10</font>
<aligny>top</aligny>
</control>
<control type="image">
<description>separator</description>
<width>102%</width>
<height>0.5</height>
<top>66</top>
<left>-10</left>
<texture colordiffuse="ff525252" border="90,3,90,3">emby-separator.png</texture>
</control>
</control>
<control type="group">
<description>Buttons</description>
<top>335</top>
<control type="button" id="200">
<description>Sign in</description>
<texturenofocus border="5" colordiffuse="ff0b8628">box.png</texturenofocus>
<texturefocus border="5" colordiffuse="ff13a134">box.png</texturefocus>
<label>[UPPERCASE][B]$ADDON[plugin.video.emby 30605][/B][/UPPERCASE]</label>
<font>font10</font>
<textcolor>ffa6a6a6</textcolor>
<focusedcolor>white</focusedcolor>
<align>center</align>
<width>100%</width>
<height>50</height>
<ondown>201</ondown>
</control>
<control type="button" id="201">
<description>Cancel</description>
<texturenofocus border="5" colordiffuse="ff464646">box.png</texturenofocus>
<texturefocus border="5" colordiffuse="ff525252">box.png</texturefocus>
<label>[UPPERCASE][B]$ADDON[plugin.video.emby 30606][/B][/UPPERCASE]</label>
<font>font10</font>
<textcolor>ffa6a6a6</textcolor>
<focusedcolor>white</focusedcolor>
<align>center</align>
<width>100%</width>
<height>50</height>
<top>55</top>
<onup>200</onup>
</control>
</control>
</control>
</control>
</controls>
</window>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<window>
<defaultcontrol always="false">200</defaultcontrol>
<defaultcontrol always="true">200</defaultcontrol>
<zorder>0</zorder>
<include>dialogeffect</include>
<controls>
@ -13,21 +13,41 @@
<control type="group">
<width>600</width>
<left>33%</left>
<left>35%</left>
<top>15%</top>
<control type="image">
<description>Background box</description>
<texture border="6" colordiffuse="ff111111">box.png</texture>
<texture colordiffuse="ff111111">white.png</texture>
<width>600</width>
<height>700</height>
</control>
<control type="group" id="202">
<top>705</top>
<visible>False</visible>
<control type="image">
<description>Error box</description>
<texture colordiffuse="ff222222">white.png</texture>
<width>100%</width>
<height>50</height>
</control>
<control type="label" id="203">
<description>Error message</description>
<textcolor>white</textcolor>
<font>font10</font>
<aligny>center</aligny>
<align>center</align>
<height>50</height>
</control>
</control>
<control type="image">
<description>Emby logo</description>
<texture>logo-white.png</texture>
<width>160</width>
<height>49</height>
<top>20</top>
<top>30</top>
<left>25</left>
</control>
@ -47,7 +67,7 @@
<top>190</top>
<control type="label">
<description>Username email</description>
<label>$ADDON[plugin.video.emby 30601]</label>
<label>$ADDON[plugin.video.emby 30543]</label>
<textcolor>ffa6a6a6</textcolor>
<font>font10</font>
<aligny>top</aligny>
@ -59,7 +79,7 @@
<height>0.5</height>
<top>66</top>
<left>-10</left>
<texture colordiffuse="ff222222" border="90,3,90,3">separator.png</texture>
<texture colordiffuse="ff525252" border="90,3,90,3">emby-separator.png</texture>
</control>
</control>
@ -80,7 +100,7 @@
<height>0.5</height>
<top>66</top>
<left>-10</left>
<texture colordiffuse="ff222222" border="90,3,90,3">separator.png</texture>
<texture colordiffuse="ff525252" border="90,3,90,3">emby-separator.png</texture>
</control>
</control>
@ -89,10 +109,12 @@
<top>385</top>
<control type="button" id="200">
<description>Sign in</description>
<texturenofocus border="5" colordiffuse="green">box.png</texturenofocus>
<texturefocus border="5" colordiffuse="green">box.png</texturefocus>
<texturenofocus border="5" colordiffuse="ff0b8628">box.png</texturenofocus>
<texturefocus border="5" colordiffuse="ff13a134">box.png</texturefocus>
<label>[UPPERCASE][B]$ADDON[plugin.video.emby 30605][/B][/UPPERCASE]</label>
<font>font10</font>
<textcolor>ffa6a6a6</textcolor>
<focusedcolor>white</focusedcolor>
<align>center</align>
<width>100%</width>
<height>50</height>
@ -100,11 +122,13 @@
</control>
<control type="button" id="201">
<description>Later</description>
<description>Cancel</description>
<texturenofocus border="5" colordiffuse="ff464646">box.png</texturenofocus>
<texturefocus border="5" colordiffuse="ff464646">box.png</texturefocus>
<texturefocus border="5" colordiffuse="ff525252">box.png</texturefocus>
<label>[UPPERCASE][B]$ADDON[plugin.video.emby 30606][/B][/UPPERCASE]</label>
<font>font10</font>
<textcolor>ffa6a6a6</textcolor>
<focusedcolor>white</focusedcolor>
<align>center</align>
<width>100%</width>
<height>50</height>
@ -124,30 +148,32 @@
<wrapmultiline>true</wrapmultiline>
<aligny>top</aligny>
<width>340</width>
<height>100%</height>
</control>
<control type="image">
<description>qrcode</description>
<texture>qrcode_disclaimer.png</texture>
<width>140</width>
<height>140</height>
<top>10</top>
<left>360</left>
</control>
<control type="group">
<control type="label">
<description>Scan me</description>
<label>[UPPERCASE]$ADDON[plugin.video.emby 30604][/UPPERCASE]</label>
<font>font12</font>
<textcolor>ff0b8628</textcolor>
<aligny>top</aligny>
<width>200</width>
<top>120</top>
<left>230</left>
</control>
<control type="label">
<description>Scan me</description>
<label>[UPPERCASE]$ADDON[plugin.video.emby 30604][/UPPERCASE]</label>
<font>font12</font>
<textcolor>green</textcolor>
<align>right</align>
<aligny>top</aligny>
<top>120</top>
<right>160</right>
<control type="image">
<description>qrcode</description>
<texture>qrcode_disclaimer.png</texture>
<width>140</width>
<height>140</height>
<top>10</top>
<left>360</left>
</control>
</control>
</control>
</control>
</control>
</controls>
</window>

View file

@ -0,0 +1,154 @@
<?xml version="1.0" encoding="UTF-8"?>
<window>
<defaultcontrol always="true">200</defaultcontrol>
<zorder>0</zorder>
<include>dialogeffect</include>
<controls>
<control type="image">
<description>Background fade</description>
<width>100%</width>
<height>100%</height>
<texture>emby-bg-fade.png</texture>
</control>
<control type="group">
<width>600</width>
<left>35%</left>
<top>20%</top>
<control type="image">
<description>Background box</description>
<texture colordiffuse="ff111111">white.png</texture>
<width>600</width>
<height>525</height>
</control>
<control type="group" id="202">
<top>530</top>
<visible>False</visible>
<control type="image">
<description>Error box</description>
<texture colordiffuse="ff222222">white.png</texture>
<width>100%</width>
<height>50</height>
</control>
<control type="label" id="203">
<description>Error message</description>
<textcolor>white</textcolor>
<font>font10</font>
<aligny>center</aligny>
<align>center</align>
<height>50</height>
</control>
</control>
<control type="image">
<description>Emby logo</description>
<texture>logo-white.png</texture>
<aspectratio>keep</aspectratio>
<width>120</width>
<height>49</height>
<top>30</top>
<left>25</left>
</control>
<control type="group">
<width>500</width>
<left>50</left>
<control type="label">
<description>Connect to server</description>
<label>$ADDON[plugin.video.emby 30614]</label>
<textcolor>white</textcolor>
<font>font12</font>
<aligny>top</aligny>
<align>center</align>
<width>100%</width>
<top>100</top>
</control>
<control type="group">
<top>150</top>
<control type="label">
<description>Host</description>
<label>$ADDON[plugin.video.emby 30615]</label>
<textcolor>ffa6a6a6</textcolor>
<font>font10</font>
<aligny>top</aligny>
</control>
<control type="image">
<description>separator</description>
<width>102%</width>
<height>0.5</height>
<top>66</top>
<left>-10</left>
<texture colordiffuse="ff525252" border="90,3,90,3">emby-separator.png</texture>
</control>
<control type="label">
<description>Host example</description>
<label>192.168.1.100 or https://myserver.com</label>
<textcolor>ff464646</textcolor>
<font>font10</font>
<aligny>top</aligny>
<top>70</top>
</control>
</control>
<control type="group">
<description>Port</description>
<top>275</top>
<control type="label">
<description>Port label</description>
<label>$ADDON[plugin.video.emby 30030]</label>
<textcolor>ffa6a6a6</textcolor>
<font>font10</font>
<aligny>top</aligny>
</control>
<control type="image">
<description>separator</description>
<width>102%</width>
<height>0.5</height>
<top>66</top>
<left>-10</left>
<texture colordiffuse="ff525252" border="90,3,90,3">emby-separator.png</texture>
</control>
</control>
<control type="group">
<description>Buttons</description>
<top>380</top>
<control type="button" id="200">
<description>Connect</description>
<texturenofocus border="5" colordiffuse="ff0b8628">box.png</texturenofocus>
<texturefocus border="5" colordiffuse="ff13a134">box.png</texturefocus>
<label>[UPPERCASE][B]$ADDON[plugin.video.emby 30616][/B][/UPPERCASE]</label>
<font>font10</font>
<textcolor>ffa6a6a6</textcolor>
<focusedcolor>white</focusedcolor>
<align>center</align>
<width>100%</width>
<height>50</height>
<ondown>201</ondown>
</control>
<control type="button" id="201">
<description>Cancel</description>
<texturenofocus border="5" colordiffuse="ff464646">box.png</texturenofocus>
<texturefocus border="5" colordiffuse="ff525252">box.png</texturefocus>
<label>[UPPERCASE][B]$ADDON[plugin.video.emby 30606][/B][/UPPERCASE]</label>
<font>font10</font>
<textcolor>ffa6a6a6</textcolor>
<focusedcolor>white</focusedcolor>
<align>center</align>
<width>100%</width>
<height>50</height>
<top>55</top>
<onup>200</onup>
</control>
</control>
</control>
</control>
</controls>
</window>

View file

@ -0,0 +1,280 @@
<?xml version="1.0" encoding="UTF-8"?>
<window>
<defaultcontrol always="true">205</defaultcontrol>
<zorder>0</zorder>
<include>dialogeffect</include>
<controls>
<control type="image">
<description>Background fade</description>
<width>100%</width>
<height>100%</height>
<texture>emby-bg-fade.png</texture>
</control>
<control type="group">
<width>450</width>
<left>38%</left>
<top>15%</top>
<control type="image">
<description>Background box</description>
<texture colordiffuse="ff111111">white.png</texture>
<width>450</width>
<height>710</height>
</control>
<control type="image">
<description>Emby logo</description>
<texture>logo-white.png</texture>
<aspectratio>keep</aspectratio>
<width>120</width>
<height>49</height>
<top>30</top>
<left>25</left>
</control>
<control type="group">
<description>User info</description>
<top>70</top>
<width>350</width>
<left>50</left>
<control type="image" id="150">
<description>User image</description>
<texture diffuse="user_image.png">userflyoutdefault.png</texture>
<aspectratio>keep</aspectratio>
<align>center</align>
<width>100%</width>
<height>70</height>
<top>40</top>
</control>
<control type="image" id="204">
<description>Busy animation</description>
<align>center</align>
<top>23</top>
<width>100%</width>
<height>105</height>
<visible>False</visible>
<texture colordiffuse="ff13a134">fading_circle.png</texture>
<aspectratio>keep</aspectratio>
<animation effect="rotate" start="360" end="0" center="auto" time="2000" loop="true" condition="true">conditional</animation>
</control>
<control type="label" id="151">
<description>Welcome user</description>
<textcolor>white</textcolor>
<font>font12</font>
<align>center</align>
<aligny>top</aligny>
<top>120</top>
<width>100%</width>
<height>50</height>
</control>
<control type="image">
<description>separator</description>
<width>102%</width>
<height>0.5</height>
<top>165</top>
<left>-10</left>
<texture colordiffuse="ff525252" border="90,3,90,3">emby-separator.png</texture>
</control>
<control type="label">
<description>Select server</description>
<textcolor>ffa6a6a6</textcolor>
<label>$ADDON[plugin.video.emby 30607]</label>
<font>font10</font>
<align>center</align>
<aligny>top</aligny>
<top>170</top>
<width>100%</width>
<height>50</height>
</control>
</control>
<control type="group">
<top>290</top>
<width>100%</width>
<height>184</height>
<control type="list" id="155">
<description>Connect servers</description>
<focusposition>0</focusposition>
<width>100%</width>
<height>100%</height>
<top>10</top>
<left>55</left>
<onup>155</onup>
<ondown condition="Control.IsVisible(205)">205</ondown>
<ondown condition="!Control.IsVisible(205)">206</ondown>
<onleft condition="Control.IsVisible(205)">205</onleft>
<onleft condition="!Control.IsVisible(205)">206</onleft>
<onright>155</onright>
<pagecontrol>60</pagecontrol>
<scrolltime tween="sine" easing="out">250</scrolltime>
<itemlayout height="46">
<control type="group">
<width>45</width>
<height>45</height>
<control type="image">
<description>Network</description>
<aspectratio>keep</aspectratio>
<texture>network.png</texture>
<visible>StringCompare(ListItem.Property(server_type),network)</visible>
</control>
<control type="image">
<description>Wifi</description>
<aspectratio>keep</aspectratio>
<texture>wifi.png</texture>
<visible>StringCompare(ListItem.Property(server_type),wifi)</visible>
</control>
</control>
<control type="label">
<width>300</width>
<height>40</height>
<left>55</left>
<font>font10</font>
<aligny>center</aligny>
<textcolor>ff838383</textcolor>
<info>ListItem.Label</info>
</control>
</itemlayout>
<focusedlayout height="46">
<control type="group">
<width>45</width>
<height>45</height>
<control type="image">
<description>Network</description>
<aspectratio>keep</aspectratio>
<texture>network.png</texture>
<visible>StringCompare(ListItem.Property(server_type),network)</visible>
</control>
<control type="image">
<description>Wifi</description>
<aspectratio>keep</aspectratio>
<texture>wifi.png</texture>
<visible>StringCompare(ListItem.Property(server_type),wifi)</visible>
</control>
</control>
<control type="label">
<width>300</width>
<height>40</height>
<left>55</left>
<font>font10</font>
<aligny>center</aligny>
<textcolor>white</textcolor>
<info>ListItem.Label</info>
<visible>Control.HasFocus(155)</visible>
</control>
<control type="label">
<width>300</width>
<height>40</height>
<left>55</left>
<font>font10</font>
<aligny>center</aligny>
<textcolor>ff838383</textcolor>
<info>ListItem.Label</info>
<visible>!Control.HasFocus(155)</visible>
</control>
</focusedlayout>
</control>
<control type="scrollbar" id="60">
<left>395</left>
<top>10</top>
<width>5</width>
<height>100%</height>
<onleft>155</onleft>
<onup>60</onup>
<ondown>60</ondown>
<texturesliderbackground colordiffuse="ff000000" border="4">box.png</texturesliderbackground>
<texturesliderbar colordiffuse="ff222222" border="4">box.png</texturesliderbar>
<texturesliderbarfocus colordiffuse="ff222222" border="4">box.png</texturesliderbarfocus>
<showonepage>false</showonepage>
</control>
<control type="group">
<top>100%</top>
<height>220</height>
<control type="group">
<top>45</top>
<height>150</height>
<control type="button" id="205">
<visible>True</visible>
<description>Sign in Connect</description>
<texturenofocus border="5" colordiffuse="ff0b8628">box.png</texturenofocus>
<texturefocus border="5" colordiffuse="ff13a134">box.png</texturefocus>
<label>[UPPERCASE][B]$ADDON[plugin.video.emby 30600][/B][/UPPERCASE]</label>
<font>font10</font>
<textcolor>ffa6a6a6</textcolor>
<focusedcolor>white</focusedcolor>
<align>center</align>
<width>350</width>
<height>50</height>
<left>50</left>
<onup>155</onup>
<ondown>206</ondown>
</control>
<control type="button" id="206">
<description>Manually add server</description>
<texturenofocus border="5" colordiffuse="ff464646">box.png</texturenofocus>
<texturefocus border="5" colordiffuse="ff525252">box.png</texturefocus>
<label>[UPPERCASE][B]$ADDON[plugin.video.emby 30611][/B][/UPPERCASE]</label>
<font>font10</font>
<textcolor>ffa6a6a6</textcolor>
<focusedcolor>white</focusedcolor>
<align>center</align>
<top>55</top>
<width>350</width>
<height>50</height>
<left>50</left>
<onup condition="Control.IsVisible(205)">205</onup>
<onup condition="!Control.IsVisible(205)">155</onup>
<ondown>201</ondown>
</control>
<control type="button" id="201">
<description>Cancel</description>
<texturenofocus border="5" colordiffuse="ff464646">box.png</texturenofocus>
<texturefocus border="5" colordiffuse="ff525252">box.png</texturefocus>
<label>[UPPERCASE][B]$ADDON[plugin.video.emby 30606][/B][/UPPERCASE]</label>
<font>font10</font>
<textcolor>ffa6a6a6</textcolor>
<focusedcolor>white</focusedcolor>
<align>center</align>
<top>110</top>
<width>350</width>
<height>50</height>
<left>50</left>
<onup>206</onup>
</control>
</control>
<control type="group" id="202">
<top>100%</top>
<visible>False</visible>
<control type="image">
<description>Message box</description>
<texture colordiffuse="ff222222">white.png</texture>
<width>100%</width>
<height>50</height>
<top>20</top>
</control>
<control type="label" id="203">
<description>Message</description>
<textcolor>white</textcolor>
<font>font10</font>
<aligny>center</aligny>
<align>center</align>
<height>50</height>
<top>20</top>
</control>
</control>
</control>
</control>
</control>
</controls>
</window>

View file

@ -0,0 +1,198 @@
<?xml version="1.0" encoding="UTF-8"?>
<window>
<defaultcontrol always="true">155</defaultcontrol>
<zorder>0</zorder>
<include>dialogeffect</include>
<controls>
<control type="image">
<description>Background fade</description>
<width>100%</width>
<height>100%</height>
<texture>emby-bg-fade.png</texture>
</control>
<control type="group">
<width>715</width>
<left>32%</left>
<top>20%</top>
<control type="image">
<description>Background box</description>
<texture border="6" colordiffuse="ff111111">white.png</texture>
<width>100%</width>
<height>525</height>
</control>
<control type="image">
<description>Emby logo</description>
<texture>logo-white.png</texture>
<aspectratio>keep</aspectratio>
<width>120</width>
<height>49</height>
<top>30</top>
<left>25</left>
</control>
<control type="label">
<description>Please sign in</description>
<label>$ADDON[plugin.video.emby 30612]</label>
<textcolor>white</textcolor>
<font>font12</font>
<aligny>top</aligny>
<align>center</align>
<top>80</top>
<width>100%</width>
</control>
<control type="group">
<top>100</top>
<width>620</width>
<height>245</height>
<left>50</left>
<control type="list" id="155">
<description>Select User</description>
<focusposition>0</focusposition>
<width>100%</width>
<top>40</top>
<onleft>155</onleft>
<onright>155</onright>
<ondown>200</ondown>
<pagecontrol>60</pagecontrol>
<orientation>horizontal</orientation>
<scrolltime tween="sine" easing="out">250</scrolltime>
<itemlayout width="155">
<control type="group">
<width>150</width>
<control type="image">
<description>User image</description>
<colordiffuse>ff888888</colordiffuse>
<info>ListItem.Icon</info>
<aspectratio>keep</aspectratio>
<width>100%</width>
<height>150</height>
</control>
<control type="image">
<description>Background label</description>
<texture colordiffuse="ff222222">white.png</texture>
<width>100%</width>
<height>50</height>
<top>150</top>
</control>
<control type="label">
<width>100%</width>
<align>center</align>
<height>50</height>
<top>150</top>
<font>font10</font>
<textcolor>white</textcolor>
<info>ListItem.Label</info>
</control>
</control>
</itemlayout>
<focusedlayout width="155">
<control type="group">
<width>150</width>
<control type="image">
<description>User image</description>
<info>ListItem.Icon</info>
<aspectratio>keep</aspectratio>
<width>100%</width>
<height>150</height>
<visible>Control.HasFocus(155)</visible>
</control>
<control type="image">
<description>User image</description>
<colordiffuse>ff888888</colordiffuse>
<info>ListItem.Icon</info>
<aspectratio>keep</aspectratio>
<width>100%</width>
<height>150</height>
<visible>!Control.HasFocus(155)</visible>
</control>
<control type="image">
<description>Background label</description>
<texture colordiffuse="ff333333">white.png</texture>
<width>100%</width>
<height>50</height>
<top>150</top>
<visible>Control.HasFocus(155)</visible>
</control>
<control type="image">
<description>Background label</description>
<texture colordiffuse="ff222222">white.png</texture>
<width>100%</width>
<height>50</height>
<top>150</top>
<visible>!Control.HasFocus(155)</visible>
</control>
<control type="label">
<width>100%</width>
<align>center</align>
<height>50</height>
<top>150</top>
<font>font10</font>
<textcolor>white</textcolor>
<info>ListItem.Label</info>
</control>
</control>
</focusedlayout>
</control>
<control type="scrollbar" id="60">
<top>100%</top>
<width>615</width>
<height>5</height>
<onleft>155</onleft>
<onleft>60</onleft>
<onright>60</onright>
<texturesliderbackground colordiffuse="ff000000" border="4">box.png</texturesliderbackground>
<texturesliderbar colordiffuse="ff222222" border="4">box.png</texturesliderbar>
<texturesliderbarfocus colordiffuse="ff222222" border="4">box.png</texturesliderbarfocus>
<showonepage>false</showonepage>
<orientation>horizontal</orientation>
</control>
<control type="group">
<width>615</width>
<height>325</height>
<top>100%</top>
<control type="group">
<control type="button" id="200">
<description>Manual Login button</description>
<texturenofocus border="5" colordiffuse="ff464646">box.png</texturenofocus>
<texturefocus border="5" colordiffuse="ff585858">box.png</texturefocus>
<label>[UPPERCASE][B]$ADDON[plugin.video.emby 30540][/B][/UPPERCASE]</label>
<align>center</align>
<width>100%</width>
<height>50</height>
<top>35</top>
<font>font10</font>
<textcolor>ffa6a6a6</textcolor>
<focusedcolor>white</focusedcolor>
<ondown>201</ondown>
<onup>155</onup>
</control>
<control type="button" id="201">
<description>Cancel</description>
<texturenofocus border="5" colordiffuse="ff464646">box.png</texturenofocus>
<texturefocus border="5" colordiffuse="ff585858">box.png</texturefocus>
<label>[UPPERCASE][B]$ADDON[plugin.video.emby 30606][/B][/UPPERCASE]</label>
<font>font10</font>
<textcolor>ffa6a6a6</textcolor>
<focusedcolor>white</focusedcolor>
<align>center</align>
<width>100%</width>
<height>50</height>
<top>90</top>
<onup>200</onup>
</control>
</control>
</control>
</control>
</control>
</controls>
</window>

View file

@ -0,0 +1,109 @@
<?xml version="1.0" encoding="UTF-8"?>
<window>
<defaultcontrol always="true">155</defaultcontrol>
<zorder>0</zorder>
<include>dialogeffect</include>
<controls>
<control type="image">
<description>Background fade</description>
<width>100%</width>
<height>100%</height>
<texture>emby-bg-fade.png</texture>
</control>
<control type="group">
<width>450</width>
<left>38%</left>
<top>36%</top>
<control type="image">
<description>Background box</description>
<texture colordiffuse="ff111111">white.png</texture>
<height>90</height>
</control>
<control type="image">
<description>Emby logo</description>
<texture>emby-icon.png</texture>
<aspectratio>keep</aspectratio>
<height>30</height>
<top>20</top>
<left>370</left>
</control>
<control type="image" id="150">
<description>User image</description>
<texture diffuse="user_image.png"></texture>
<aspectratio>keep</aspectratio>
<height>34</height>
<top>20</top>
<left>285</left>
</control>
<control type="image">
<description>separator</description>
<width>100%</width>
<height>0.5</height>
<top>70</top>
<left>-5</left>
<texture colordiffuse="ff484848" border="90,3,90,3">emby-separator.png</texture>
</control>
<control type="group">
<width>450</width>
<top>90</top>
<control type="list" id="155">
<width>100%</width>
<height>100%</height>
<align>center</align>
<onup>155</onup>
<ondown>155</ondown>
<onleft>155</onleft>
<onright>155</onright>
<scrolltime>200</scrolltime>
<itemlayout height="55">
<control type="image">
<description>Background box</description>
<width>450</width>
<texture colordiffuse="ff111111">white.png</texture>
</control>
<control type="label">
<width>400</width>
<font>font11</font>
<textcolor>ff525252</textcolor>
<left>25</left>
<align>center</align>
<aligny>center</aligny>
<info>ListItem.Label</info>
</control>
</itemlayout>
<focusedlayout height="55">
<control type="image">
<description>Background box</description>
<width>450</width>
<texture colordiffuse="ff111111">white.png</texture>
</control>
<control type="image">
<width>400</width>
<left>25</left>
<align>center</align>
<texture border="5" colordiffuse="ff222222">white.png</texture>
<visible>Control.HasFocus(155)</visible>
<animation effect="fade" time="300">Visible</animation>
<animation effect="fade" time="300">Hidden</animation>
</control>
<control type="label">
<width>400</width>
<font>font11</font>
<textcolor>white</textcolor>
<left>25</left>
<align>center</align>
<aligny>center</aligny>
<info>ListItem.Label</info>
</control>
</focusedlayout>
</control>
</control>
</control>
</controls>
</window>

View file

@ -1,129 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<window>
<defaultcontrol always="true">8011</defaultcontrol>
<zorder>0</zorder>
<controls>
<control type="group">
<right>560</right>
<top>140</top>
<width>800</width>
<height>800</height>
<control type="group">
<control type="image">
<texture border="5" colordiffuse="ff111111">box.png</texture>
<height>100</height>
</control>
<control type="image">
<texture border="5" colordiffuse="ff222222">box.png</texture>
<top>100</top>
<height>700</height>
</control>
<control type="image" id="8002">
<description>user image</description>
<width>80</width>
<height>100</height>
</control>
<control type="label" id="8001" description="name">
<left>90</left>
<top>30</top>
<height>40</height>
<width>20%</width>
<align>left</align>
<font>font16</font>
<textcolor>ffeeeeee</textcolor>
</control>
<!-- -->
<control type="label" description="Title">
<left>320</left>
<top>30</top>
<align>left</align>
<height>40</height>
<width>100%</width>
<font>font16</font>
<textcolor>ffeeeeee</textcolor>
<label>User Preferences</label>
</control>
<control type="image">
<description>separator</description>
<left>-10</left>
<top>103</top>
<width>101%</width>
<height>1</height>
<texture colordiffuse="ffffffff" border="90,3,90,3">separator.png</texture>
</control>
<control type="grouplist">
<top>50</top>
<height>600</height>
<orientation>vertical</orientation>
<align>left</align>
<itemgap>20</itemgap>
<control type="group">
<control type="radiobutton" id="8011">
<left>8</left>
<ondown>8012</ondown>
<onup>8012</onup>
<top>100</top>
<width>785</width>
<align>left</align>
<height>70</height>
<textureradiofocus colordiffuse="B3dddddd">radio-on.png</textureradiofocus>
<textureradionofocus colordiffuse="1Fdddddd">radio-off.png</textureradionofocus>
<texturefocus border="5" colordiffuse="ff0385b5">white.png</texturefocus>
<radioposx>750</radioposx>
<radiowidth>32</radiowidth>
<radioheight>32</radioheight>
<textoffsetx>30</textoffsetx>
<textcolor>B3dddddd</textcolor>
<label>Enable cinema mode</label>
</control>
</control>
</control>
<!-- buttons -->
<control type="image">
<description>separator</description>
<bottom>70</bottom>
<left>-10</left>
<width>101%</width>
<height>1</height>
<texture border="90,3,90,3">separator.png</texture>
</control>
<control type="button" id="8012">
<description>Save</description>
<left>150</left>
<bottom>20</bottom>
<width>230</width>
<onup>8011</onup>
<onleft>8013</onleft>
<onright>8013</onright>
<font>font14</font>
<label>Save</label>
<focusedcolor>FFededed</focusedcolor>
<disabledcolor>B3dddddd</disabledcolor>
<selectedcolor>FF000000</selectedcolor>
<height>40</height>
<textcolor>ff333333</textcolor>
<texturefocus colordiffuse="ff0385b5" border="5">box.png</texturefocus>
<texturenofocus colordiffuse="B3dddddd" border="5">box.png</texturenofocus>
</control>
<control type="button" id="8013">
<description>Cancel</description>
<left>430</left>
<bottom>20</bottom>
<width>230</width>
<onup>8011</onup>
<onleft>8012</onleft>
<onright>8012</onright>
<font>font14</font>
<label>222</label>
<focusedcolor>FFededed</focusedcolor>
<disabledcolor>B3dddddd</disabledcolor>
<selectedcolor>FF000000</selectedcolor>
<height>40</height>
<textcolor>ff333333</textcolor>
<texturefocus colordiffuse="ff0385b5" border="5">box.png</texturefocus>
<texturenofocus colordiffuse="B3dddddd" border="5">box.png</texturenofocus>
</control>
</control>
</control>
</controls>
</window>

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

View file

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 727 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 662 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -50,7 +50,7 @@ import PlexCompanion
import loghandler
loghandler.config()
log = logging.getLogger("PLEX.default")
log = logging.getLogger("PLEX.service")
addonName = 'PlexKodiConnect'
###############################################################################
@ -77,6 +77,8 @@ class Service():
window('plex_logLevel', value=str(logLevel))
window('plex_kodiProfile',
value=xbmc.translatePath("special://profile"))
window('plex_context',
value='true' if settings('enableContext') == "true" else "")
# Initial logging
log.warn("======== START %s ========" % addonName)