I18n and house-keeping (#6)

* convert strings.xml to strings.po for improved translation support
* set blank heading for error
* i18n: map ints to strings for readability/maintenance
* simple_logging - add prefix, add log.warning
* remove unneccesary Addon() instances
* uniform whitespace
* remove log warning, i18n log failure as error
* settings - create as needed
This commit is contained in:
anxdpanic 2017-05-29 06:19:33 -04:00 committed by Shaun
parent 69eed6a599
commit 7e7e9184cd
18 changed files with 1136 additions and 735 deletions

View File

@ -3,13 +3,11 @@
from resources.lib.simple_logging import SimpleLogging
from resources.lib.functions import mainEntryPoint
log = SimpleLogging("EmbyCon.default")
log = SimpleLogging('default')
log.info("About to enter mainEntryPoint()")
mainEntryPoint()
#clear done and exit.
#sys.modules.clear()
# clear done and exit.
# sys.modules.clear()

View File

@ -0,0 +1,411 @@
msgid ""
msgstr ""
"Project-Id-Version: EmbyCon\n"
"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: en\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
msgctxt "#30000"
msgid "Server Address: "
msgstr ""
msgctxt "#30001"
msgid "Server Port: "
msgstr ""
msgctxt "#30004"
msgid "Log Level: "
msgstr ""
msgctxt "#30005"
msgid "Username: "
msgstr ""
msgctxt "#30006"
msgid "Password: "
msgstr ""
msgctxt "#30007"
msgid "Samba Username: "
msgstr ""
msgctxt "#30008"
msgid "Samba Password: "
msgstr ""
msgctxt "#30010"
msgid "Enable performance profiling"
msgstr ""
msgctxt "#30011"
msgid "Detect Server"
msgstr ""
msgctxt "#30012"
msgid "Change User"
msgstr ""
msgctxt "#30014"
msgid "Emby"
msgstr ""
msgctxt "#30015"
msgid "Network"
msgstr ""
msgctxt "#30016"
msgid "Device Name"
msgstr ""
msgctxt "#30022"
msgid "Advanced"
msgstr ""
msgctxt "#30024"
msgid "Username:"
msgstr ""
msgctxt "#30025"
msgid "Password:"
msgstr ""
msgctxt "#30044"
msgid "Incorrect Username/Password"
msgstr ""
msgctxt "#30045"
msgid "Username not found"
msgstr ""
msgctxt "#30052"
msgid "Deleting"
msgstr ""
msgctxt "#30053"
msgid "Waiting for server to delete"
msgstr ""
msgctxt "#30060"
msgid "%s (Secured)"
msgstr ""
msgctxt "#30061"
msgid "%s (User-defined)"
msgstr ""
msgctxt "#30062"
msgid "Hidden user (User-input)"
msgstr ""
msgctxt "#30063"
msgid "N/A"
msgstr ""
msgctxt "#30091"
msgid "Confirm file delete?"
msgstr ""
msgctxt "#30092"
msgid "Delete this item? This action will delete media and associated data files."
msgstr ""
msgctxt "#30110"
msgid "Interface"
msgstr ""
msgctxt "#30114"
msgid "On Resume Jump Back Seconds"
msgstr ""
msgctxt "#30116"
msgid "Add Item and Played Counts"
msgstr ""
msgctxt "#30117"
msgid "Background Art Refresh Rate (seconds)"
msgstr ""
msgctxt "#30118"
msgid "Add Resume Percent"
msgstr ""
msgctxt "#30119"
msgid "Add Episode Number"
msgstr ""
msgctxt "#30120"
msgid "Show Load Progress"
msgstr ""
msgctxt "#30125"
msgid "Done"
msgstr ""
msgctxt "#30126"
msgid "Processing Item : "
msgstr ""
msgctxt "#30128"
msgid "Play Error"
msgstr ""
msgctxt "#30129"
msgid "This item is not playable"
msgstr ""
msgctxt "#30135"
msgid "Error"
msgstr ""
msgctxt "#30136"
msgid "EmbyCon service is not running"
msgstr ""
msgctxt "#30137"
msgid "Please restart Kodi"
msgstr ""
msgctxt "#30138"
msgid "Cache Emby Data Locally"
msgstr ""
msgctxt "#30139"
msgid "No Media Type Set"
msgstr ""
msgctxt "#30150"
msgid "Skin does not support setting views"
msgstr ""
msgctxt "#30151"
msgid "Select item action (Requires Restart)"
msgstr ""
msgctxt "#30162"
msgid "Add Season Number"
msgstr ""
msgctxt "#30166"
msgid "Select Server"
msgstr ""
msgctxt "#30167"
msgid "Server Detection Succeeded"
msgstr ""
msgctxt "#30168"
msgid "Found server"
msgstr ""
msgctxt "#30169"
msgid "Address: "
msgstr ""
msgctxt "#30180"
msgid "Select User"
msgstr ""
msgctxt "#30200"
msgid "URL error: %s"
msgstr ""
msgctxt "#30201"
msgid "Unable to connect to server"
msgstr ""
msgctxt "#30202"
msgid "Error Extracting Server host:port"
msgstr ""
msgctxt "#30203"
msgid "Error in ArtworkRotationThread"
msgstr ""
msgctxt "#30204"
msgid "Unable to connect to host"
msgstr ""
msgctxt "#30205"
msgid "Error in LoadMenuOptionsThread"
msgstr ""
msgctxt "#30206"
msgid "Playback Type"
msgstr ""
msgctxt "#30207"
msgid "Playback"
msgstr ""
msgctxt "#30208"
msgid "Playback Bitrate (Kbits)"
msgstr ""
msgctxt "#30209"
msgid "File Direct Path"
msgstr ""
msgctxt "#30210"
msgid "HTTP Direct Stream"
msgstr ""
msgctxt "#30211"
msgid "HTTP Transcode"
msgstr ""
msgctxt "#30230"
msgid "Default View"
msgstr ""
msgctxt "#30231"
msgid "Movies"
msgstr ""
msgctxt "#30232"
msgid "BoxSets"
msgstr ""
msgctxt "#30233"
msgid "Series"
msgstr ""
msgctxt "#30234"
msgid "Seasons"
msgstr ""
msgctxt "#30235"
msgid "Episodes"
msgstr ""
msgctxt "#30236"
msgid "Save"
msgstr ""
msgctxt "#30237"
msgid "Start from beginning"
msgstr ""
msgctxt "#30238"
msgid "Default Sort"
msgstr ""
msgctxt "#30247"
msgid "Widgets"
msgstr ""
msgctxt "#30248"
msgid "Emby - Movies"
msgstr ""
msgctxt "#30249"
msgid "Emby - TV Shows"
msgstr ""
msgctxt "#30250"
msgid "Unknown"
msgstr ""
msgctxt "#30251"
msgid "Movies (Genre)"
msgstr ""
msgctxt "#30252"
msgid "Movies (A-Z)"
msgstr ""
msgctxt "#30253"
msgid "Change User"
msgstr ""
msgctxt "#30254"
msgid "Show Settings"
msgstr ""
msgctxt "#30255"
msgid "Set Default Views"
msgstr ""
msgctxt "#30256"
msgid "Movies - All"
msgstr ""
msgctxt "#30257"
msgid "Movies - Recently Added"
msgstr ""
msgctxt "#30258"
msgid "Movies - In Progress"
msgstr ""
msgctxt "#30259"
msgid "Movies - Favorites"
msgstr ""
msgctxt "#30260"
msgid "BoxSets"
msgstr ""
msgctxt "#30261"
msgid "TV Shows - All"
msgstr ""
msgctxt "#30262"
msgid "TV Shows - Favorites"
msgstr ""
msgctxt "#30263"
msgid "Episodes - Recently Added"
msgstr ""
msgctxt "#30264"
msgid "Episodes - In Progress"
msgstr ""
msgctxt "#30265"
msgid "Episodes - Next Up"
msgstr ""
msgctxt "#30266"
msgid "Upcoming TV"
msgstr ""
msgctxt "#30267"
msgid " - In Progress"
msgstr ""
msgctxt "#30268"
msgid " - Recently Added"
msgstr ""
msgctxt "#30269"
msgid "Movies - Random"
msgstr ""
msgctxt "#30270"
msgid "Emby: Mark watched"
msgstr ""
msgctxt "#30271"
msgid "Emby: Mark unwatched"
msgstr ""
msgctxt "#30272"
msgid "Emby: Set favourite"
msgstr ""
msgctxt "#30273"
msgid "Emby: Unset favourite"
msgstr ""
msgctxt "#30274"
msgid "Emby: Delete"
msgstr ""
msgctxt "#30280"
msgid "Missing Title"
msgstr ""

View File

@ -1,121 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<strings>
<string id="30000">Server Address: </string>
<string id="30030">Server Port: </string>
<string id="30004">Log Level: </string>
<string id="30005">Username: </string>
<string id="30006">Password: </string>
<string id="30007">Samba Username: </string>
<string id="30008">Samba Password: </string>
<string id="30010">Enable performance profiling</string>
<string id="30011">Detect Server</string>
<string id="30012">Change User</string>
<string id="30014">Emby</string>
<string id="30015">Network</string>
<string id="30016">Device Name</string>
<string id="30022">Advanced</string>
<string id="30024">Username:</string>
<string id="30025">Password:</string>
<string id="30044">Incorrect Username/Password</string>
<string id="30045">Username not found</string>
<string id="30053">Waiting for server to delete</string>
<string id="30060">%s (Secured)</string>
<string id="30061">%s (User-defined)</string>
<string id="30062">Hidden user (User-input)</string>
<string id="30063">N/A</string>
<string id="30091">Confirm file delete?</string>
<string id="30092">Delete this item? This action will delete media and associated data files.</string>
<string id="30110">Interface</string>
<string id="30114">On Resume Jump Back Seconds</string>
<string id="30116">Add Item and Played Counts</string>
<string id="30117">Background Art Refresh Rate (seconds)</string>
<string id="30118">Add Resume Percent</string>
<string id="30119">Add Episode Number</string>
<string id="30120">Show Load Progress</string>
<string id="30125">Done</string>
<string id="30126">Processing Item : </string>
<string id="30128">Play Error</string>
<string id="30129">This item is not playable</string>
<string id="30135">Error</string>
<string id="30136">EmbyCon service is not running</string>
<string id="30137">Please restart Kodi</string>
<string id="30138">Cache Emby Data Locally</string>
<string id="30139">No Media Type Set</string>
<string id="30150">Skin does not support setting views</string>
<string id="30151">Select item action (Requires Restart)</string>
<string id="30162">Add Season Number</string>
<string id="30166">Select Server</string>
<string id="30167">Server Detection Succeeded</string>
<string id="30168">Found server</string>
<string id="30169">Address: </string>
<string id="30180">Select User</string>
<string id="30200">URL error: %s</string>
<string id="30201">Unable to connect to server</string>
<string id="30202">Error Extracting Server host:port</string>
<string id="30203">Error in ArtworkRotationThread</string>
<string id="30204">Unable to connect to host</string>
<string id="30205">Error in LoadMenuOptionsThread</string>
<string id="30206">Playback Type</string>
<string id="30207">Playback</string>
<string id="30208">Playback Bitrate (Kbits)</string>
<string id="30209">File Direct Path</string>
<string id="30210">HTTP Direct Stream</string>
<string id="30211">HTTP Transcode</string>
<string id="30230">Default View</string>
<string id="30231">Movies</string>
<string id="30232">BoxSets</string>
<string id="30233">Series</string>
<string id="30234">Seasons</string>
<string id="30235">Episodes</string>
<string id="30236">Save</string>
<string id="30237">Start from beginning</string>
<string id="30238">Default Sort</string>
<string id="30247">Widgets</string>
<string id="30248">Emby - Movies</string>
<string id="30249">Emby - TV Shows</string>
<string id="30250">Unknown</string>
<string id="30251">Movies (Genre)</string>
<string id="30252">Movies (A-Z)</string>
<string id="30253">Change User</string>
<string id="30254">Show Settings</string>
<string id="30255">Set Default Views</string>
<string id="30256">Movies - All</string>
<string id="30257">Movies - Recently Added</string>
<string id="30258">Movies - In Progress</string>
<string id="30259">Movies - Favorites</string>
<string id="30260">BoxSets</string>
<string id="30261">TV Shows - All</string>
<string id="30262">TV Shows - Favorites</string>
<string id="30263">Episodes - Recently Added</string>
<string id="30264">Episodes - In Progress</string>
<string id="30265">Episodes - Next Up</string>
<string id="30266">Upcoming TV</string>
<string id="30267"> - In Progress</string>
<string id="30268"> - Recently Added</string>
<string id="30269">Movies - Random</string>
<string id="30270">Emby: Mark watched</string>
<string id="30271">Emby: Mark unwatched</string>
<string id="30272">Emby: Set favourite</string>
<string id="30273">Emby: Unset favourite</string>
<string id="30274">Emby: Delete</string>
<string id="30280">Missing Title</string>
</strings>

View File

@ -8,12 +8,13 @@ import xbmcvfs
from kodi_utils import HomeWindow
from simple_logging import SimpleLogging
log = SimpleLogging("EmbyCon." + __name__)
log = SimpleLogging(__name__)
__addon__ = xbmcaddon.Addon(id="plugin.video.embycon")
class ClientInformation():
def getDeviceId(self):
WINDOW = HomeWindow()
client_id = WINDOW.getProperty("client_id")
@ -35,9 +36,9 @@ class ClientInformation():
WINDOW.setProperty("client_id", client_id)
return client_id
def getVersion(self):
version = xbmcaddon.Addon(id="plugin.video.embycon").getAddonInfo("version")
version = __addon__.getAddonInfo("version")
return version
def getClient(self):

View File

@ -13,27 +13,27 @@ from simple_logging import SimpleLogging
from utils import getChecksum
from kodi_utils import HomeWindow
log = SimpleLogging("EmbyCon." + __name__)
log = SimpleLogging(__name__)
class DataManager():
cacheDataResult = None
dataUrl = None
cacheDataPath = None
canRefreshNow = False
def __init__(self, *args):
log.info("DataManager __init__")
log.info("DataManager __init__")
def getCacheValidatorFromData(self, result):
result = result.get("Items")
if(result == None):
if (result == None):
result = []
itemCount = 0
unwatchedItemCount = 0
unwatchedItemCount = 0
dataHashString = ""
for item in result:
item_hash_string = getChecksum(item)
item_hash_string = str(itemCount) + "_" + item.get("Name", "-") + "_" + item_hash_string + "|"
@ -46,15 +46,15 @@ class DataManager():
m = hashlib.md5()
m.update(dataHashString)
validatorString = m.hexdigest()
log.debug("getCacheValidatorFromData : RawData : " + dataHashString)
log.debug("getCacheValidatorFromData : hashData : " + validatorString)
return validatorString
def loadJasonData(self, jsonData):
return json.loads(jsonData)
return json.loads(jsonData)
def GetContent(self, url):
__addon__ = xbmcaddon.Addon(id='plugin.video.embycon')
@ -68,25 +68,25 @@ class DataManager():
log.info("Returning Loaded Result")
return result
# first get the url hash
# first get the url hash
m = hashlib.md5()
m.update(url)
urlHash = m.hexdigest()
# build cache data path
__addondir__ = xbmc.translatePath( __addon__.getAddonInfo('profile'))
__addondir__ = xbmc.translatePath(__addon__.getAddonInfo('profile'))
if not os.path.exists(os.path.join(__addondir__, "cache")):
os.makedirs(os.path.join(__addondir__, "cache"))
cacheDataPath = os.path.join(__addondir__, "cache", urlHash)
log.info("Cache_Data_Manager:" + cacheDataPath)
# are we forcing a reload
WINDOW = HomeWindow()
force_data_reload = WINDOW.getProperty("force_data_reload") == "true"
WINDOW.clearProperty("force_data_reload")
if os.path.exists(cacheDataPath) and not force_data_reload:
# load data from cache if it is available and trigger a background
# verification process to test cache validity
@ -95,7 +95,7 @@ class DataManager():
jsonData = cachedfie.read()
cachedfie.close()
result = self.loadJasonData(jsonData)
# start a worker thread to process the cache validity
self.cacheDataResult = result
self.dataUrl = url
@ -115,34 +115,33 @@ class DataManager():
cachedfie.close()
result = self.loadJasonData(jsonData)
self.cacheManagerFinished = True
log.info("Returning Loaded Result")
log.info("Returning Loaded Result")
return result
class CacheManagerThread(threading.Thread):
class CacheManagerThread(threading.Thread):
dataManager = None
def __init__(self, *args):
threading.Thread.__init__(self, *args)
def setCacheData(self, data):
self.dataManager = data
def run(self):
log.info("CacheManagerThread Started")
cacheValidatorString = self.dataManager.getCacheValidatorFromData(self.dataManager.cacheDataResult)
log.info("Cache Validator String (" + cacheValidatorString + ")")
jsonData = DownloadUtils().downloadUrl(self.dataManager.dataUrl, suppress=False, popup=1)
loadedResult = self.dataManager.loadJasonData(jsonData)
loadedValidatorString = self.dataManager.getCacheValidatorFromData(loadedResult)
log.info("Loaded Validator String (" + loadedValidatorString + ")")
# if they dont match then save the data and trigger a content reload
if(cacheValidatorString != loadedValidatorString):
if (cacheValidatorString != loadedValidatorString):
log.info("CacheManagerThread Saving new cache data and reloading container")
cachedfie = open(self.dataManager.cacheDataPath, 'w')
cachedfie.write(jsonData)
@ -150,11 +149,11 @@ class CacheManagerThread(threading.Thread):
# we need to refresh but will wait until the main function has finished
loops = 0
while(self.dataManager.canRefreshNow == False and loops < 200):
while (self.dataManager.canRefreshNow == False and loops < 200):
log.debug("Cache_Data_Manager: Not finished yet")
xbmc.sleep(100)
loops = loops + 1
log.info("Sending container refresh (" + str(loops) + ")")
xbmc.executebuiltin("Container.Refresh")

View File

@ -13,19 +13,19 @@ import json
from kodi_utils import HomeWindow
from clientinfo import ClientInformation
from simple_logging import SimpleLogging
from translation import i18n
log = SimpleLogging(__name__)
log = SimpleLogging("EmbyCon." + __name__)
class DownloadUtils():
getString = None
def __init__(self, *args):
settings = xbmcaddon.Addon(id='plugin.video.embycon')
self.getString = settings.getLocalizedString
self.addon_name = settings.getAddonInfo('name')
self.addon = xbmcaddon.Addon(id='plugin.video.embycon')
self.addon_name = self.addon.getAddonInfo('name')
def getArtwork(self, data, art_type, parent = False, index = "0", width = 10000, height = 10000, server=None):
def getArtwork(self, data, art_type, parent=False, index="0", width=10000, height=10000, server=None):
id = data.get("Id")
'''
@ -38,32 +38,32 @@ class DownloadUtils():
id = data.get("SeriesId")
imageTag = ""
#"e3ab56fe27d389446754d0fb04910a34" # a place holder tag, needs to be in this format
# "e3ab56fe27d389446754d0fb04910a34" # a place holder tag, needs to be in this format
itemType = data.get("Type")
# for episodes always use the parent BG
if(itemType == "Episode" and art_type == "Backdrop"):
if (itemType == "Episode" and art_type == "Backdrop"):
id = data.get("ParentBackdropItemId")
bgItemTags = data.get("ParentBackdropImageTags")
if(bgItemTags != None and len(bgItemTags) > 0):
if (bgItemTags != None and len(bgItemTags) > 0):
imageTag = bgItemTags[0]
elif(art_type == "Backdrop") and (parent == True):
elif (art_type == "Backdrop") and (parent == True):
id = data.get("ParentBackdropItemId")
bgItemTags = data.get("ParentBackdropImageTags")
if(bgItemTags != None and len(bgItemTags) > 0):
if (bgItemTags != None and len(bgItemTags) > 0):
imageTag = bgItemTags[0]
elif(art_type == "Backdrop"):
elif (art_type == "Backdrop"):
BGTags = data.get("BackdropImageTags")
if(BGTags != None and len(BGTags) > 0):
if (BGTags != None and len(BGTags) > 0):
bgIndex = int(index)
imageTag = data.get("BackdropImageTags")[bgIndex]
log.debug("Background Image Tag:" + imageTag)
elif(parent == False):
if(data.get("ImageTags") != None and data.get("ImageTags").get(art_type) != None):
log.debug("Background Image Tag:" + imageTag)
elif (parent == False):
if (data.get("ImageTags") != None and data.get("ImageTags").get(art_type) != None):
imageTag = data.get("ImageTags").get(art_type)
log.debug("Image Tag:" + imageTag)
elif(parent == True):
elif (parent == True):
if (itemType == "Episode") and (art_type == 'Primary'):
tagName = 'SeriesPrimaryImageTag'
idName = 'SeriesId'
@ -75,16 +75,16 @@ class DownloadUtils():
imageTag = data.get(tagName)
log.debug("Parent Image Tag:" + imageTag)
if(imageTag == "" or imageTag == None) and (art_type != 'Banner'): # ParentTag not passed for Banner
if (imageTag == "" or imageTag == None) and (art_type != 'Banner'): # ParentTag not passed for Banner
log.debug("No Image Tag for request:" + art_type + " item:" + itemType + " parent:" + str(parent))
return ""
query = ""
artwork = "http://%s/emby/Items/%s/Images/%s/%s?MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s" % (server, id, art_type, index, width, height, imageTag, query)
log.debug("getArtwork : " + artwork)
'''
# do not return non-existing images
if ( (art_type != "Backdrop" and imageTag == "") |
@ -93,7 +93,7 @@ class DownloadUtils():
):
artwork = ''
'''
return artwork
def imageUrl(self, id, art_type, index, width, height, imageTag, server):
@ -108,17 +108,17 @@ class DownloadUtils():
str(height) + "/" + str(width) + "/0")
'''
return artwork
def getUserId(self):
WINDOW = HomeWindow()
userid = WINDOW.getProperty("userid")
if(userid != None and userid != ""):
if (userid != None and userid != ""):
log.info("EmbyCon DownloadUtils -> Returning saved UserID : " + userid)
return userid
settings = xbmcaddon.Addon(id='plugin.video.embycon')
settings = xbmcaddon.Addon('plugin.video.embycon')
port = settings.getSetting('port')
host = settings.getSetting('ipaddress')
userName = settings.getSetting('username')
@ -143,17 +143,17 @@ class DownloadUtils():
result = json.loads(jsonData)
except Exception, e:
log.info("jsonload : " + str(e) + " (" + jsonData + ")")
return ""
return ""
log.info("GETUSER_JSONDATA_02:" + str(result))
userid = ""
secure = False
for user in result:
if(user.get("Name") == userName):
if (user.get("Name") == userName):
userid = user.get("Id")
log.info("Username Found:" + user.get("Name"))
if(user.get("HasPassword") == True):
if (user.get("HasPassword") == True):
secure = True
log.info("Username Is Secure (HasPassword=True)")
break
@ -161,37 +161,37 @@ class DownloadUtils():
if (secure) or (not userid):
authOk = self.authenticate()
if (authOk == ""):
return_value = xbmcgui.Dialog().ok(self.getString(30044), self.getString(30044))
return_value = xbmcgui.Dialog().ok(self.addon_name, i18n('incorrect_user_pass'))
return ""
if not userid:
userid = WINDOW.getProperty("userid")
if userid == "":
return_value = xbmcgui.Dialog().ok(self.getString(30045),self.getString(30045))
return_value = xbmcgui.Dialog().ok(self.addon_name, i18n('username_not_found'))
log.info("userid : " + userid)
WINDOW.setProperty("userid", userid)
return userid
return userid
def authenticate(self):
WINDOW = HomeWindow()
token = WINDOW.getProperty("AccessToken")
if(token != None and token != ""):
if (token != None and token != ""):
log.info("EmbyCon DownloadUtils -> Returning saved AccessToken : " + token)
return token
settings = xbmcaddon.Addon(id='plugin.video.embycon')
settings = xbmcaddon.Addon('plugin.video.embycon')
port = settings.getSetting("port")
host = settings.getSetting("ipaddress")
if(host == None or host == "" or port == None or port == ""):
if (host == None or host == "" or port == None or port == ""):
return ""
url = "http://" + host + ":" + port + "/emby/Users/AuthenticateByName?format=json"
clientInfo = ClientInformation()
txt_mac = clientInfo.getDeviceId()
version = clientInfo.getVersion()
@ -201,9 +201,9 @@ class DownloadUtils():
deviceName = deviceName.replace("\"", "_")
authString = "Mediabrowser Client=\"" + client + "\",Device=\"" + deviceName + "\",DeviceId=\"" + txt_mac + "\",Version=\"" + version + "\""
headers = {'Accept-encoding': 'gzip', 'Authorization' : authString}
headers = {'Accept-encoding': 'gzip', 'Authorization': authString}
sha1 = hashlib.sha1(settings.getSetting('password'))
messageData = "username=" + settings.getSetting('username') + "&password=" + sha1.hexdigest()
resp = self.downloadUrl(url, postBody=messageData, method="POST", suppress=True, authenticate=False)
@ -217,7 +217,7 @@ class DownloadUtils():
except:
pass
if(accessToken != None):
if (accessToken != None):
log.info("User Authenticated : " + accessToken)
WINDOW.setProperty("AccessToken", accessToken)
WINDOW.setProperty("userid", userid)
@ -227,39 +227,39 @@ class DownloadUtils():
WINDOW.setProperty("AccessToken", "")
WINDOW.setProperty("userid", "")
return ""
def getAuthHeader(self, authenticate=True):
clientInfo = ClientInformation()
txt_mac = clientInfo.getDeviceId()
version = clientInfo.getVersion()
client = clientInfo.getClient()
settings = xbmcaddon.Addon(id='plugin.video.embycon')
settings = xbmcaddon.Addon('plugin.video.embycon')
deviceName = settings.getSetting('deviceName')
deviceName = deviceName.replace("\"", "_")
headers = {}
headers["Accept-encoding"] = "gzip"
headers["Accept-Charset"] = "UTF-8,*"
if(authenticate == False):
if (authenticate == False):
authString = "MediaBrowser Client=\"" + client + "\",Device=\"" + deviceName + "\",DeviceId=\"" + txt_mac + "\",Version=\"" + version + "\""
headers["Authorization"] = authString
headers['X-Emby-Authorization'] = authString
headers['X-Emby-Authorization'] = authString
return headers
else:
userid = self.getUserId()
authString = "MediaBrowser UserId=\"" + userid + "\",Client=\"" + client + "\",Device=\"" + deviceName + "\",DeviceId=\"" + txt_mac + "\",Version=\"" + version + "\""
headers["Authorization"] = authString
headers['X-Emby-Authorization'] = authString
headers['X-Emby-Authorization'] = authString
authToken = self.authenticate()
if(authToken != ""):
if (authToken != ""):
headers["X-MediaBrowser-Token"] = authToken
log.info("EmbyCon Authentication Header : " + str(headers))
return headers
def downloadUrl(self, url, suppress=False, postBody=None, method="GET", popup=0, authenticate=True):
log.info("downloadUrl")
link = ""
@ -272,25 +272,25 @@ class DownloadUtils():
urlsplit = 1
server = url.split('/')[serversplit]
urlPath = "/"+"/".join(url.split('/')[urlsplit:])
urlPath = "/" + "/".join(url.split('/')[urlsplit:])
log.info("DOWNLOAD_URL = " + url)
log.debug("server = "+str(server))
log.debug("urlPath = "+str(urlPath))
log.debug("server = " + str(server))
log.debug("urlPath = " + str(urlPath))
# check the server details
tokens = server.split(':')
host = tokens[0]
port = tokens[1]
if(host == "<none>" or host == "" or port == ""):
if (host == "<none>" or host == "" or port == ""):
return ""
conn = httplib.HTTPConnection(server, timeout=40)
head = self.getAuthHeader(authenticate)
log.info("HEADERS : " + str(head))
if(postBody != None):
if (postBody != None):
if isinstance(postBody, dict):
content_type = "application/json"
postBody = json.dumps(postBody)
@ -313,7 +313,7 @@ class DownloadUtils():
retData = data.read()
contentType = data.getheader('content-encoding')
log.debug("Data Len Before : " + str(len(retData)))
if(contentType == "gzip"):
if (contentType == "gzip"):
retData = StringIO.StringIO(retData)
gzipper = gzip.GzipFile(fileobj=retData)
link = gzipper.read()
@ -325,9 +325,11 @@ class DownloadUtils():
log.debug(link)
log.debug("====== 200 finished ======")
elif ( int(data.status) == 301 ) or ( int(data.status) == 302 ):
try: conn.close()
except: pass
elif (int(data.status) == 301) or (int(data.status) == 302):
try:
conn.close()
except:
pass
return data.getheader('Location')
elif int(data.status) >= 400:
@ -335,12 +337,14 @@ class DownloadUtils():
log.error(error)
if suppress is False:
if popup == 0:
xbmc.executebuiltin("Notification(%s, %s)" % (self.addon_name, self.getString(30200) % str(data.reason)))
xbmc.executebuiltin("Notification(%s, %s)" % (self.addon_name, i18n('url_error_') % str(data.reason)))
else:
xbmcgui.Dialog().ok(self.getString(30135),server)
xbmcgui.Dialog().ok(self.addon_name, i18n('url_error_') % str(data.reason))
log.error(error)
try: conn.close()
except: pass
try:
conn.close()
except:
pass
return ""
else:
link = ""
@ -349,12 +353,14 @@ class DownloadUtils():
log.error(error)
if suppress is False:
if popup == 0:
xbmc.executebuiltin("Notification(%s, %s)" % (self.addon_name, self.getString(30200) % self.getString(30201)))
xbmc.executebuiltin("Notification(%s, %s)" % (self.addon_name, i18n('url_error_') % i18n('unable_connect_server')))
else:
xbmcgui.Dialog().ok("",self.getString(30204))
xbmcgui.Dialog().ok(self.addon_name, i18n('url_error_') % i18n('unable_connect_server'))
raise
else:
try: conn.close()
except: pass
try:
conn.close()
except:
pass
return link

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@ import json
from simple_logging import SimpleLogging
log = SimpleLogging("EmbyCon." + __name__)
log = SimpleLogging(__name__)
class HomeWindow():

View File

@ -11,12 +11,13 @@ from downloadutils import DownloadUtils
from utils import getDetailsString
from kodi_utils import addMenuDirectoryItem
from simple_logging import SimpleLogging
from translation import i18n
log = SimpleLogging("EmbyCon." + __name__)
log = SimpleLogging(__name__)
downloadUtils = DownloadUtils()
__addon__ = xbmcaddon.Addon(id='plugin.video.embycon')
__language__ = __addon__.getLocalizedString
def showGenreList():
log.info("== ENTER: showGenreList() ==")
@ -57,8 +58,8 @@ def showGenreList():
url = sys.argv[0] + ("?url=" + urllib.quote('http://%s%s' % (collection['address'], collection['path'])) +
"&mode=GET_CONTENT" +
"&media_type=" + collection["media_type"])
log.info("addMenuDirectoryItem: " + collection.get('title', __language__(30250)) + " " + str(url))
addMenuDirectoryItem(collection.get('title', __language__(30250)), url, thumbnail=collection.get("thumbnail"))
log.info("addMenuDirectoryItem: " + collection.get('title', i18n('unknown')) + " " + str(url))
addMenuDirectoryItem(collection.get('title', i18n('unknown')), url, thumbnail=collection.get("thumbnail"))
xbmcplugin.endOfDirectory(int(sys.argv[1]))
@ -103,12 +104,13 @@ def showMovieAlphaList():
for collection in collections:
url = (sys.argv[0] + "?url=" + urllib.quote('http://%s%s' % (collection['address'], collection['path'])) +
"&mode=GET_CONTENT&media_type=" + collection["media_type"])
log.info("addMenuDirectoryItem: " + collection.get('title', __language__(30250)) + " " + str(url))
addMenuDirectoryItem(collection.get('title', __language__(30250)), url)
"&mode=GET_CONTENT&media_type=" + collection["media_type"])
log.info("addMenuDirectoryItem: " + collection.get('title', i18n('unknown')) + " " + str(url))
addMenuDirectoryItem(collection.get('title', i18n('unknown')), url)
xbmcplugin.endOfDirectory(int(sys.argv[1]))
def displaySections():
log.info("== ENTER: displaySections() ==")
xbmcplugin.setContent(int(sys.argv[1]), 'files')
@ -123,19 +125,20 @@ def displaySections():
collections = getCollections(detailsString)
for collection in collections:
url = (sys.argv[0] + "?url=" + urllib.quote('http://%s%s' % (collection['address'], collection['path'])) +
"&mode=GET_CONTENT&media_type=" + collection["media_type"])
log.info("addMenuDirectoryItem: " + collection.get('title', __language__(30250)) + " " + str(url))
addMenuDirectoryItem(collection.get('title', __language__(30250)), url, thumbnail=collection.get("thumbnail"))
"&mode=GET_CONTENT&media_type=" + collection["media_type"])
log.info("addMenuDirectoryItem: " + collection.get('title', i18n('unknown')) + " " + str(url))
addMenuDirectoryItem(collection.get('title', i18n('unknown')), url, thumbnail=collection.get("thumbnail"))
addMenuDirectoryItem(__language__(30251), "plugin://plugin.video.embycon/?mode=MOVIE_GENRA")
addMenuDirectoryItem(__language__(30252), "plugin://plugin.video.embycon/?mode=MOVIE_ALPHA")
addMenuDirectoryItem(__language__(30253), "plugin://plugin.video.embycon/?mode=CHANGE_USER")
addMenuDirectoryItem(__language__(30254), "plugin://plugin.video.embycon/?mode=SHOW_SETTINGS")
addMenuDirectoryItem(__language__(30255), "plugin://plugin.video.embycon/?mode=SET_DEFAULT_VIEWS")
addMenuDirectoryItem(__language__(30247), "plugin://plugin.video.embycon/?mode=WIDGETS")
addMenuDirectoryItem(i18n('movies_genre'), "plugin://plugin.video.embycon/?mode=MOVIE_GENRA")
addMenuDirectoryItem(i18n('movies_az'), "plugin://plugin.video.embycon/?mode=MOVIE_ALPHA")
addMenuDirectoryItem(i18n('change_user'), "plugin://plugin.video.embycon/?mode=CHANGE_USER")
addMenuDirectoryItem(i18n('show_settings'), "plugin://plugin.video.embycon/?mode=SHOW_SETTINGS")
addMenuDirectoryItem(i18n('set_default_views'), "plugin://plugin.video.embycon/?mode=SET_DEFAULT_VIEWS")
addMenuDirectoryItem(i18n('widgets'), "plugin://plugin.video.embycon/?mode=WIDGETS")
xbmcplugin.endOfDirectory(int(sys.argv[1]))
def getCollections(detailsString):
log.info("== ENTER: getCollections ==")
@ -171,7 +174,7 @@ def getCollections(detailsString):
jsonData = downloadUtils.downloadUrl(
htmlpath + userid + "/items?ParentId=" + parentid + "&Sortby=SortName&format=json")
log.debug("jsonData : " + jsonData)
collections=[]
collections = []
result = []
try:
@ -204,7 +207,7 @@ def getCollections(detailsString):
if collection_type == "movies":
collections.append({
'title': item_name + __language__(30267),
'title': item_name + i18n('_in_progress'),
'address': server,
'thumbnail': downloadUtils.getArtwork(item, "Primary", server=server),
'path': ('/emby/Users/' + userid + '/Items' +
@ -218,7 +221,7 @@ def getCollections(detailsString):
'media_type': collection_type})
collections.append({
'title': item_name + __language__(30268),
'title': item_name + i18n('_recently_added'),
'address': server,
'thumbnail': downloadUtils.getArtwork(item, "Primary", server=server),
'path': ('/emby/Users/' + userid + '/Items' +
@ -236,7 +239,7 @@ def getCollections(detailsString):
# Add standard nodes
item_data = {}
item_data['address'] = server
item_data['title'] = __language__(30256)
item_data['title'] = i18n('movies_all')
item_data['media_type'] = 'Movies'
item_data[
'path'] = '/emby/Users/' + userid + '/Items?Fields=' + detailsString + '&Recursive=true&IncludeItemTypes=Movie&CollapseBoxSetItems=true&ImageTypeLimit=1&format=json'
@ -244,7 +247,7 @@ def getCollections(detailsString):
item_data = {}
item_data['address'] = server
item_data['title'] = __language__(30257)
item_data['title'] = i18n('movies_recently_added')
item_data['media_type'] = 'Movies'
item_data[
'path'] = '/emby/Users/' + userid + '/Items?Limit=' + '20' + '&Recursive=true&SortBy=DateCreated&Fields=' + detailsString + '&SortOrder=Descending&Filters=IsUnplayed,IsNotFolder&IncludeItemTypes=Movie&ImageTypeLimit=1&format=json'
@ -252,7 +255,7 @@ def getCollections(detailsString):
item_data = {}
item_data['address'] = server
item_data['title'] = __language__(30258)
item_data['title'] = i18n('movies_in_progress')
item_data['media_type'] = 'Movies'
item_data[
'path'] = '/emby/Users/' + userid + '/Items?Limit=' + '20' + '&Recursive=true&Fields=' + detailsString + '&Filters=IsResumable&IncludeItemTypes=Movie&ImageTypeLimit=1&format=json'
@ -260,7 +263,7 @@ def getCollections(detailsString):
item_data = {}
item_data['address'] = server
item_data['title'] = __language__(30259)
item_data['title'] = i18n('movies_favorites')
item_data['media_type'] = 'Movies'
item_data[
'path'] = '/emby/Users/' + userid + '/Items?Fields=' + detailsString + '&Recursive=true&Filters=IsFavorite&IncludeItemTypes=Movie&CollapseBoxSetItems=true&ImageTypeLimit=1&format=json'
@ -268,7 +271,7 @@ def getCollections(detailsString):
item_data = {}
item_data['address'] = server
item_data['title'] = __language__(30260)
item_data['title'] = i18n('movies_boxsets')
item_data['media_type'] = 'BoxSets'
item_data[
'path'] = '/emby/Users/' + userid + '/Items?Recursive=true&Fields=' + detailsString + '&IncludeItemTypes=BoxSet&ImageTypeLimit=1&format=json'
@ -276,7 +279,7 @@ def getCollections(detailsString):
item_data = {}
item_data['address'] = server
item_data['title'] = __language__(30261)
item_data['title'] = i18n('tvshows_all')
item_data['media_type'] = 'tvshows'
item_data[
'path'] = '/emby/Users/' + userid + '/Items?Fields=' + detailsString + '&Recursive=true&IncludeItemTypes=Series&ImageTypeLimit=1&format=json'
@ -284,7 +287,7 @@ def getCollections(detailsString):
item_data = {}
item_data['address'] = server
item_data['title'] = __language__(30262)
item_data['title'] = i18n('tvshows_favorites')
item_data['media_type'] = 'tvshows'
item_data[
'path'] = '/emby/Users/' + userid + '/Items?Fields=' + detailsString + '&Recursive=true&Filters=IsFavorite&IncludeItemTypes=Series&ImageTypeLimit=1&format=json'
@ -292,7 +295,7 @@ def getCollections(detailsString):
item_data = {}
item_data['address'] = server
item_data['title'] = __language__(30263)
item_data['title'] = i18n('episodes_recently_added')
item_data['media_type'] = 'Season'
item_data[
'path'] = '/emby/Users/' + userid + '/Items?Limit=' + '20' + '&Recursive=true&SortBy=DateCreated&Fields=' + detailsString + '&SortOrder=Descending&Filters=IsUnplayed,IsNotFolder&IsVirtualUnaired=false&IsMissing=False&IncludeItemTypes=Episode&ImageTypeLimit=1&format=json'
@ -300,7 +303,7 @@ def getCollections(detailsString):
item_data = {}
item_data['address'] = server
item_data['title'] = __language__(30264)
item_data['title'] = i18n('episodes_in_progress')
item_data['media_type'] = 'Episodes'
item_data[
'path'] = '/emby/Users/' + userid + '/Items?Limit=' + '20' + '&Recursive=true&Fields=' + detailsString + '&Filters=IsResumable&IncludeItemTypes=Episode&ImageTypeLimit=1&format=json'
@ -308,7 +311,7 @@ def getCollections(detailsString):
item_data = {}
item_data['address'] = server
item_data['title'] = __language__(30265)
item_data['title'] = i18n('episodes_up_next')
item_data['media_type'] = 'Episodes'
item_data[
'path'] = '/emby/Shows/NextUp/?Userid=' + userid + '&Limit=' + '20' + '&Recursive=true&Fields=' + detailsString + '&Filters=IsUnplayed,IsNotFolder&IsVirtualUnaired=false&IsMissing=False&IncludeItemTypes=Episode&ImageTypeLimit=1&format=json'
@ -316,7 +319,7 @@ def getCollections(detailsString):
item_data = {}
item_data['address'] = server
item_data['title'] = __language__(30266)
item_data['title'] = i18n('upcoming_tv')
item_data['media_type'] = 'Episodes'
item_data[
'path'] = '/emby/Users/' + userid + '/Items?Recursive=true&SortBy=PremiereDate&Fields=' + detailsString + '&SortOrder=Ascending&Filters=IsUnplayed&IsVirtualUnaired=true&IsNotFolder&IncludeItemTypes=Episode&ImageTypeLimit=1&format=json'
@ -326,14 +329,14 @@ def getCollections(detailsString):
def showWidgets():
addMenuDirectoryItem(__language__(30248), 'plugin://plugin.video.embycon/?mode=SHOW_CONTENT&item_type=Movie&media_type=Movies')
addMenuDirectoryItem(__language__(30249), 'plugin://plugin.video.embycon/?mode=SHOW_CONTENT&item_type=Series&media_type=TVShows')
addMenuDirectoryItem(i18n('emby_movies'), 'plugin://plugin.video.embycon/?mode=SHOW_CONTENT&item_type=Movie&media_type=Movies')
addMenuDirectoryItem(i18n('emby_tvshows'), 'plugin://plugin.video.embycon/?mode=SHOW_CONTENT&item_type=Series&media_type=TVShows')
addMenuDirectoryItem(__language__(30257), 'plugin://plugin.video.embycon/?mode=WIDGET_CONTENT&type=recent_movies')
addMenuDirectoryItem(__language__(30258), 'plugin://plugin.video.embycon/?mode=WIDGET_CONTENT&type=inprogress_movies')
addMenuDirectoryItem(__language__(30269), 'plugin://plugin.video.embycon/?mode=WIDGET_CONTENT&type=random_movies')
addMenuDirectoryItem(__language__(30263), 'plugin://plugin.video.embycon/?mode=WIDGET_CONTENT&type=recent_episodes')
addMenuDirectoryItem(__language__(30264), 'plugin://plugin.video.embycon/?mode=WIDGET_CONTENT&type=inprogress_episodes')
addMenuDirectoryItem(__language__(30265), 'plugin://plugin.video.embycon/?mode=WIDGET_CONTENT&type=nextup_episodes')
addMenuDirectoryItem(i18n('movies_recently_added'), 'plugin://plugin.video.embycon/?mode=WIDGET_CONTENT&type=recent_movies')
addMenuDirectoryItem(i18n('movies_in_progress'), 'plugin://plugin.video.embycon/?mode=WIDGET_CONTENT&type=inprogress_movies')
addMenuDirectoryItem(i18n('movies_random'), 'plugin://plugin.video.embycon/?mode=WIDGET_CONTENT&type=random_movies')
addMenuDirectoryItem(i18n('episodes_recently_added'), 'plugin://plugin.video.embycon/?mode=WIDGET_CONTENT&type=recent_episodes')
addMenuDirectoryItem(i18n('episodes_in_progress'), 'plugin://plugin.video.embycon/?mode=WIDGET_CONTENT&type=inprogress_episodes')
addMenuDirectoryItem(i18n('episodes_up_next'), 'plugin://plugin.video.embycon/?mode=WIDGET_CONTENT&type=nextup_episodes')
xbmcplugin.endOfDirectory(int(sys.argv[1]))

View File

@ -13,18 +13,18 @@ from downloadutils import DownloadUtils
from resume_dialog import ResumeDialog
from utils import PlayUtils, getArt
from kodi_utils import HomeWindow
from translation import i18n
log = SimpleLogging("EmbyCon." + __name__)
__addon__ = xbmcaddon.Addon(id='plugin.video.embycon')
__language__ = __addon__.getLocalizedString
log = SimpleLogging(__name__)
downloadUtils = DownloadUtils()
def playFile(id, auto_resume):
log.info("playFile id(" + str(id) + ") resume(" + str(auto_resume) + ")")
userid = downloadUtils.getUserId()
settings = xbmcaddon.Addon(id='plugin.video.embycon')
settings = xbmcaddon.Addon('plugin.video.embycon')
addon_path = settings.getAddonInfo('path')
playback_type = settings.getSetting("playback_type")
@ -73,7 +73,7 @@ def playFile(id, auto_resume):
home_window = HomeWindow()
home_window.setProperty("PlaybackType_" + id, playback_type_string)
listItem = xbmcgui.ListItem(label=result.get("Name", __language__(30280)), path=playurl)
listItem = xbmcgui.ListItem(label=result.get("Name", i18n('missing_title')), path=playurl)
listItem = setListItemProps(id, listItem, result, server)
@ -95,11 +95,11 @@ def playFile(id, auto_resume):
time.sleep(1)
while xbmc.Player().getTime() < (seekTime - 5):
#xbmc.Player().pause()
# xbmc.Player().pause()
xbmc.sleep(100)
xbmc.Player().seekTime(seekTime)
xbmc.sleep(100)
#xbmc.Player().play()
# xbmc.Player().play()
def setListItemProps(id, listItem, result, server):
@ -119,7 +119,7 @@ def setListItemProps(id, listItem, result, server):
# play info
details = {
'title': result.get("Name", __language__(30280)),
'title': result.get("Name", i18n('missing_title')),
'plot': result.get("Overview")
}
@ -131,4 +131,4 @@ def setListItemProps(id, listItem, result, server):
listItem.setInfo("Video", infoLabels=details)
return listItem
return listItem

View File

@ -1,16 +1,14 @@
# Gnu General Public License - see LICENSE.TXT
import xbmcgui
import xbmcaddon
from simple_logging import SimpleLogging
from translation import i18n
log = SimpleLogging(__name__)
log = SimpleLogging("EmbyCon." + __name__)
__addon__ = xbmcaddon.Addon(id='plugin.video.embycon')
__language__ = __addon__.getLocalizedString
class ResumeDialog(xbmcgui.WindowXMLDialog):
resumePlay = -1
resumeTimeStamp = ""
@ -21,31 +19,27 @@ class ResumeDialog(xbmcgui.WindowXMLDialog):
def onInit(self):
self.action_exitkeys_id = [10, 13]
self.getControl(3010).setLabel(self.resumeTimeStamp)
self.getControl(3011).setLabel(__language__(30237))
self.getControl(3011).setLabel(i18n('start_from_beginning'))
def onFocus(self, controlId):
def onFocus(self, controlId):
pass
def doAction(self, actionID):
pass
def onClick(self, controlID):
if(controlID == 3010):
if (controlID == 3010):
self.resumePlay = 0
self.close()
if(controlID == 3011):
if (controlID == 3011):
self.resumePlay = 1
self.close()
pass
def setResumeTime(self, timeStamp):
self.resumeTimeStamp = timeStamp
def getResumeAction(self):
return self.resumePlay

View File

@ -11,29 +11,30 @@ import xbmc
from kodi_utils import HomeWindow
from downloadutils import DownloadUtils
from simple_logging import SimpleLogging
from translation import i18n
log = SimpleLogging("EmbyCon." + __name__)
log = SimpleLogging(__name__)
__addon__ = xbmcaddon.Addon(id='plugin.video.embycon')
__language__ = __addon__.getLocalizedString
__addon_name__ = __addon__.getAddonInfo('name')
downloadUtils = DownloadUtils()
def getServerDetails():
log.debug("Getting Server Details from Network")
MESSAGE = "who is EmbyServer?"
MULTI_GROUP = ("<broadcast>", 7359)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(6.0)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 10) #timeout
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 10) # timeout
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
sock.setsockopt(socket.IPPROTO_IP, socket.SO_REUSEADDR, 1)
log.debug("MutliGroup : " + str(MULTI_GROUP))
log.debug("Sending UDP Data : " + MESSAGE)
sock.sendto(MESSAGE, MULTI_GROUP)
@ -77,8 +78,8 @@ def checkServer(force=False, change_user=False, notify=False):
serverNames = []
for server in serverInfo:
serverNames.append(server.get("Name", __language__(30063)))
return_index = xbmcgui.Dialog().select(__language__(30166), serverNames)
serverNames.append(server.get("Name", i18n('n/a')))
return_index = xbmcgui.Dialog().select(i18n('select_server'), serverNames)
if (return_index == -1):
xbmc.executebuiltin("ActivateWindow(Home)")
@ -98,7 +99,8 @@ def checkServer(force=False, change_user=False, notify=False):
settings.setSetting("ipaddress", server_address)
if notify:
xbmcgui.Dialog().ok(__language__(30167), __language__(30168), __language__(30169) + server_address, __language__(30030) + server_port)
xbmcgui.Dialog().ok(i18n('server_detect_succeeded'), i18n('found_server'),
i18n('address:') + server_address, i18n('server_port:') + server_port)
# we need to change the user
current_username = settings.getSetting("username")
@ -123,29 +125,29 @@ def checkServer(force=False, change_user=False, notify=False):
user_list.append(name)
if (user.get("HasPassword") is True):
secured.append(True)
name = __language__(30060) % name
name = i18n('username_secured') % name
else:
secured.append(False)
names.append(name)
if (len(current_username) > 0) and (not any(n == current_username for n in user_list)):
names.insert(0, __language__(30061) % current_username)
names.insert(0, i18n('username_userdefined') % current_username)
user_list.insert(0, current_username)
secured.insert(0, True)
names.insert(0, __language__(30062))
names.insert(0, i18n('username_userinput'))
user_list.insert(0, '')
secured.insert(0, True)
log.debug("User List : " + str(names))
log.debug("User List : " + str(user_list))
return_value = xbmcgui.Dialog().select(__language__(30180), names)
return_value = xbmcgui.Dialog().select(i18n('select_user'), names)
if (return_value > -1):
log.debug("Selected User Index : " + str(return_value))
if return_value == 0:
kb = xbmc.Keyboard()
kb.setHeading(__language__(30005))
kb.setHeading(i18n('username:'))
kb.doModal()
if kb.isConfirmed():
selected_user = kb.getText()
@ -162,7 +164,7 @@ def checkServer(force=False, change_user=False, notify=False):
settings.setSetting("username", selected_user)
if secured[return_value] is True:
kb = xbmc.Keyboard()
kb.setHeading(__language__(30006))
kb.setHeading(i18n('password:'))
kb.setHiddenInput(True)
kb.doModal()
if kb.isConfirmed():

View File

@ -3,16 +3,17 @@
import xbmc
import xbmcaddon
class SimpleLogging():
class SimpleLogging():
level = 0
name = ""
def __init__(self, name):
settings = xbmcaddon.Addon(id='plugin.video.embycon')
prefix = settings.getAddonInfo('name')
log_level = settings.getSetting('logLevel')
self.level = int(log_level)
self.name = name
self.name = prefix + '.' + name
def getLevel(self):
return self.level
@ -21,26 +22,25 @@ class SimpleLogging():
return "LogLevel: " + str(self.level)
def error(self, msg):
if(self.level >= 0):
if (self.level >= 0):
try:
xbmc.log(self.format(msg, "ERROR"), level=xbmc.LOGNOTICE)
except UnicodeEncodeError:
xbmc.log(self.format(msg, "ERROR").encode('utf-8'), level=xbmc.LOGNOTICE)
def info(self, msg):
if(self.level >= 1):
if (self.level >= 1):
try:
xbmc.log(self.format(msg, "INFO"), level=xbmc.LOGNOTICE)
except UnicodeEncodeError:
xbmc.log(self.format(msg, "INFO").encode('utf-8'), level=xbmc.LOGNOTICE)
def debug(self, msg):
if(self.level >= 2):
if (self.level >= 2):
try:
xbmc.log(self.format(msg, "DEBUG"), level=xbmc.LOGNOTICE)
except UnicodeEncodeError:
xbmc.log(self.format(msg, "DEBUG").encode('utf-8'), level=xbmc.LOGNOTICE)
def format(self, msg, levelValue):
return self.name + "(" + str(levelValue) + ") -> " + msg
return self.name + "(" + str(levelValue) + ") -> " + msg

View File

@ -0,0 +1,81 @@
import xbmcaddon
from simple_logging import SimpleLogging
log = SimpleLogging(__name__)
addon = xbmcaddon.Addon()
def i18n(string_id):
try:
return addon.getLocalizedString(STRINGS[string_id]).encode('utf-8', 'ignore')
except Exception as e:
log.error('Failed String Lookup: %s (%s)' % (string_id, e))
return string_id
STRINGS = {
'server_port:': 30001,
'username:': 30005,
'password:': 30006,
'incorrect_user_pass': 30044,
'username_not_found': 30045,
'deleting': 30052,
'waiting_server_delete': 30053,
'username_secured': 30060,
'username_userdefined': 30061,
'username_userinput': 30062,
'n/a': 30063,
'confirm_file_delete': 30091,
'file_delete_confirm': 30092,
'done': 30125,
'processing_item:': 30126,
'error': 30135,
'service_not_running': 30136,
'restart_kodi': 30137,
'no_media_type': 30139,
'select_server': 30166,
'server_detect_succeeded': 30167,
'found_server': 30168,
'address:': 30169,
'select_user': 30180,
'url_error_': 30200,
'unable_connect_server': 30201,
'default_view': 30230,
'movies': 30231,
'boxsets': 30232,
'series': 30233,
'seasons': 30234,
'episodes': 30235,
'save': 30236,
'start_from_beginning': 30237,
'default_sort': 30238,
'widgets': 30247,
'emby_movies': 30248,
'emby_tvshows': 30249,
'unknown': 30250,
'movies_genre': 30251,
'movies_az': 30252,
'change_user': 30253,
'show_settings': 30254,
'set_default_views': 30255,
'movies_all': 30256,
'movies_recently_added': 30257,
'movies_in_progress': 30258,
'movies_favorites': 30259,
'movies_boxsets': 30260,
'tvshows_all': 30261,
'tvshows_favorites': 30262,
'episodes_recently_added': 30263,
'episodes_in_progress': 30264,
'episodes_up_next': 30265,
'upcoming_tv': 30266,
'_in_progress': 30267,
'_recently_added': 30268,
'movies_random': 30269,
'emby_mark_watched': 30270,
'emby_mark_unwatched': 30271,
'emby_set_favorite': 30272,
'emby_unset_favorite': 30273,
'emby_delete': 30274,
'missing_title': 30280
}

View File

@ -6,9 +6,10 @@ from downloadutils import DownloadUtils
from simple_logging import SimpleLogging
from clientinfo import ClientInformation
#define our global download utils
# define our global download utils
downloadUtils = DownloadUtils()
log = SimpleLogging("EmbyCon." + __name__)
log = SimpleLogging(__name__)
###########################################################################
class PlayUtils():
@ -76,9 +77,10 @@ class PlayUtils():
def getDetailsString():
detailsString = "EpisodeCount,SeasonCount,Path,Genres,Studios,CumulativeRunTimeTicks,MediaStreams,Overview,Etag"
#detailsString = "EpisodeCount,SeasonCount,Path,Genres,CumulativeRunTimeTicks"
# detailsString = "EpisodeCount,SeasonCount,Path,Genres,CumulativeRunTimeTicks"
return detailsString
def getChecksum(item):
userdata = item['UserData']
checksum = "%s_%s_%s_%s_%s_%s_%s" % (
@ -93,6 +95,7 @@ def getChecksum(item):
return checksum
def getArt(item, server, widget=False):
art = {
'thumb': '',

View File

@ -8,17 +8,17 @@ import xbmcaddon
import json
from simple_logging import SimpleLogging
from translation import i18n
log = SimpleLogging("EmbyCon." + __name__)
log = SimpleLogging(__name__)
__addon__ = xbmcaddon.Addon(id='plugin.video.embycon')
__language__ = __addon__.getLocalizedString
def loadSkinDefaults():
defaultData = {}
# load current default views
# add a hash of xbmc.getSkinDir() to file name to make it skin specific
__addondir__ = xbmc.translatePath( __addon__.getAddonInfo('profile'))
__addondir__ = xbmc.translatePath(__addon__.getAddonInfo('profile'))
view_list_path = os.path.join(__addondir__, "default_views.json")
if os.path.exists(view_list_path):
dataFile = open(view_list_path, 'r')
@ -28,8 +28,8 @@ def loadSkinDefaults():
return defaultData
class DefaultViews(xbmcgui.WindowXMLDialog):
viewData = {}
sortData = {"Title": "title", "Date": "date"}
defaultView = {}
@ -41,36 +41,35 @@ class DefaultViews(xbmcgui.WindowXMLDialog):
def onInit(self):
self.action_exitkeys_id = [10, 13]
# load skin views
addonSettings = xbmcaddon.Addon(id='plugin.video.embycon')
addonPath = addonSettings.getAddonInfo('path')
addonPath = __addon__.getAddonInfo('path')
skin_view_file = os.path.join(addonPath, "resources", "data", "skin_views.json")
log.info("Loading skin views form: " + skin_view_file)
dataFile = open(skin_view_file, 'r')
jsonData = dataFile.read()
dataFile.close()
defaultViewData = json.loads(jsonData)
defaultViewData = json.loads(jsonData)
log.info("Loaded skin views: " + str(defaultViewData))
skin_used = xbmc.getSkinDir()
log.info("Current skin: " + skin_used)
skin_views = defaultViewData.get(skin_used, None)
log.info("Current skin views: " + str(skin_views))
self.viewData = skin_views
# load current default views
savedData = loadSkinDefaults()
self.defaultView = savedData.get("view", {})
self.defaultSort = savedData.get("sort", {})
self.getControl(3110).setLabel(__language__(30236))
self.getControl(3019).setLabel(__language__(30238))
self.getControl(3020).setLabel(__language__(30230))
self.getControl(3021).setLabel(__language__(30231))
self.getControl(3022).setLabel(__language__(30232))
self.getControl(3023).setLabel(__language__(30233))
self.getControl(3024).setLabel(__language__(30234))
self.getControl(3025).setLabel(__language__(30235))
self.getControl(3110).setLabel(i18n('save'))
self.getControl(3019).setLabel(i18n('default_sort'))
self.getControl(3020).setLabel(i18n('default_view'))
self.getControl(3021).setLabel(i18n('movies'))
self.getControl(3022).setLabel(i18n('boxsets'))
self.getControl(3023).setLabel(i18n('series'))
self.getControl(3024).setLabel(i18n('seasons'))
self.getControl(3025).setLabel(i18n('episodes'))
# set default values
name = self.getViewNameById(self.defaultView.get("Movies"))
@ -82,7 +81,7 @@ class DefaultViews(xbmcgui.WindowXMLDialog):
name = self.getViewNameById(self.defaultView.get("Seasons"))
self.getControl(3013).setLabel(name)
name = self.getViewNameById(self.defaultView.get("Episodes"))
self.getControl(3014).setLabel(name)
self.getControl(3014).setLabel(name)
name = self.getSortNameById(self.defaultSort.get("Movies"))
self.getControl(3050).setLabel(name)
@ -95,9 +94,9 @@ class DefaultViews(xbmcgui.WindowXMLDialog):
name = self.getSortNameById(self.defaultSort.get("Episodes"))
self.getControl(3054).setLabel(name)
def onFocus(self, controlId):
def onFocus(self, controlId):
pass
def doAction(self, actionID):
pass
@ -112,22 +111,22 @@ class DefaultViews(xbmcgui.WindowXMLDialog):
return "None"
def getViewNameById(self, viewId):
if(viewId == None):
if (viewId == None):
return "None"
for name, id in self.viewData.iteritems():
if id == viewId:
return name
return "None"
def getNextViewName(self, current):
keys = list(self.viewData.keys())
if(current not in keys):
if (current not in keys):
return keys[0]
index = keys.index(current)
if(index > -1 and index < len(keys)-1):
if (index > -1 and index < len(keys) - 1):
return keys[index + 1]
else:
return keys[0]
@ -144,7 +143,7 @@ class DefaultViews(xbmcgui.WindowXMLDialog):
return keys[0]
def onClick(self, controlID):
if controlID >= 3010 and controlID <= 3014:
control = self.getControl(controlID)
control.setLabel(self.getNextViewName(control.getLabel()))
@ -154,7 +153,7 @@ class DefaultViews(xbmcgui.WindowXMLDialog):
control.setLabel(self.getNextSortName(control.getLabel()))
elif controlID == 3110:
self.setViewId("Movies", 3010)
self.setViewId("BoxSets", 3011)
self.setViewId("Series", 3012)
@ -166,30 +165,29 @@ class DefaultViews(xbmcgui.WindowXMLDialog):
self.setSortId("Series", 3052)
self.setSortId("Seasons", 3053)
self.setSortId("Episodes", 3054)
__addon__ = xbmcaddon.Addon(id='plugin.video.embycon')
__addondir__ = xbmc.translatePath( __addon__.getAddonInfo('profile'))
__addondir__ = xbmc.translatePath(__addon__.getAddonInfo('profile'))
view_list_path = os.path.join(__addondir__, "default_views.json")
dataFile = open(view_list_path, 'w')
defaults_data = {"view": self.defaultView, "sort": self.defaultSort}
stringdata = json.dumps(defaults_data)
dataFile.write(stringdata)
dataFile.close()
dataFile.close()
self.close()
pass
def setViewId(self, viewName, labelId):
viewId = self.viewData.get(self.getControl(labelId).getLabel())
if(viewId == None):
if (viewId == None):
return
else:
self.defaultView[viewName] = viewId
def setSortId(self, sortName, labelId):
sortId = self.sortData.get(self.getControl(labelId).getLabel())
if(sortId == None):
if (sortId == None):
return
else:
self.defaultSort[sortName] = sortId

View File

@ -2,7 +2,7 @@
<settings>
<category label="30014">
<setting id="ipaddress" type="text" label="30000" default="&lt;none&gt;" visible="true" enable="true" />
<setting id="port" type="text" label="30030" default="8096" visible="true" enable="true" />
<setting id="port" type="text" label="30001" default="8096" visible="true" enable="true" />
<setting label="30011" type="action" action="RunScript(plugin.video.embycon,0,?mode=DETECT_SERVER_USER)" option="close"/>
<setting type="sep" />
<setting id="username" type="text" label="30024" />

View File

@ -17,7 +17,7 @@ home_window.clearProperty("userid")
home_window.clearProperty("AccessToken")
home_window.clearProperty("Params")
log = SimpleLogging("EmbyCon.service")
log = SimpleLogging('service')
download_utils = DownloadUtils()
# auth the service
@ -26,14 +26,15 @@ try:
except Exception, e:
pass
def hasData(data):
if data is None or len(data) == 0 or data == "None":
return False
else:
return True
def sendProgress():
def sendProgress():
playing_file = xbmc.Player().getPlayingFile()
play_data = monitor.played_information.get(playing_file)
@ -76,21 +77,20 @@ def sendProgress():
def stopAll(played_information):
if len(played_information) == 0:
return
log.info("played_information : " + str(played_information))
for item_url in played_information:
data = played_information.get(item_url)
if data is not None:
log.info("item_url : " + item_url)
log.info("item_data : " + str(data))
current_possition = data.get("currentPossition")
emby_item_id = data.get("item_id")
if hasData(emby_item_id):
log.info("Playback Stopped at: " + str(int(current_possition * 10000000)))
@ -108,21 +108,20 @@ def stopAll(played_information):
download_utils.downloadUrl(url, postBody=postdata, method="POST")
played_information.clear()
class Service(xbmc.Player):
class Service(xbmc.Player):
played_information = {}
def __init__(self, *args):
log.info("Starting monitor service: " + str(args))
self.played_information = {}
pass
def onPlayBackStarted(self):
# Will be called when xbmc starts playing a file
stopAll(self.played_information)
current_playing_file = xbmc.Player().getPlayingFile()
log.info("onPlayBackStarted: " + current_playing_file)
@ -158,7 +157,7 @@ class Service(xbmc.Player):
data["paused"] = False
data["playback_type"] = playback_type
self.played_information[current_playing_file] = data
log.info("ADDING_FILE : " + current_playing_file)
log.info("ADDING_FILE : " + str(self.played_information))
@ -204,7 +203,7 @@ class Service(xbmc.Player):
monitor = Service()
last_progress_update = datetime.today()
while not xbmc.abortRequested:
home_window = HomeWindow()
@ -217,7 +216,7 @@ while not xbmc.abortRequested:
if sec_diff > 10:
sendProgress()
last_progress_update = datetime.today()
except Exception, e:
log.error("Exception in Playback Monitor : " + str(e))
pass