changes to comply with Kodi repo rules

This commit is contained in:
sfaulds
2017-07-08 10:34:30 +10:00
parent 1f07af13de
commit 2fce0e85c1
24 changed files with 177 additions and 1011 deletions

View File

@@ -18,7 +18,7 @@
<forum>https://emby.media/community/index.php?/topic/46651-embycon/</forum>
<website>https://emby.media/community/index.php?/topic/46651-embycon/</website>
<source>https://github.com/faush01/plugin.video.embycon</source>
<summary lang="en">View and play your Emby media library.</summary>
<description lang="en">An addon to allow you to view and playback your Emby (www.emby.media) Movie and TV Show collection.</description>
<summary lang="en_GB">View and play your Emby media library.</summary>
<description lang="en_GB">An addon to allow you to view and playback your Emby (www.emby.media) Movie and TV Show collection.</description>
</extension>
</addon>

View File

@@ -2,21 +2,12 @@
from resources.lib.simple_logging import SimpleLogging
from resources.lib.functions import mainEntryPoint
from resources.lib.ga_client import GoogleAnalytics, log_error
log = SimpleLogging('default')
log.info("About to enter mainEntryPoint()")
log.debug("About to enter mainEntryPoint()")
try:
mainEntryPoint()
except Exception as error:
ga = GoogleAnalytics()
err_strings = ga.formatException()
ga.sendEventData("Exception", err_strings[0], err_strings[1])
log.error(str(error))
log.error(str(err_strings))
raise
mainEntryPoint()
# clear done and exit.
# sys.modules.clear()

BIN
icon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

@@ -1,5 +0,0 @@
{
"skin.estuary" : {"None" : -1, "List" : 50, "Poster" : 51, "IconWall" : 52, "Shift" : 53, "InfoWall" : 54, "WideList" : 55, "Wall" : 500, "Banner" : 501, "FanArt" : 502},
"skin.confluence" : {"None" : -1, "List" : 50, "Big list" : 51, "Thumbnail" : 500, "Poster" : 500, "Fanart" : 508, "Media info" : 504, "Media info 2" : 503, "Media info 3" : 515, "Wide" : 505},
"skin.titan" : {"None" : -1, "List" : 50, "Big list" : 51, "Horizontal Panel" : 52, "Panel Details" : 53, "Panel" : 54, "Banner List" : 55, "Banner Plex" : 56, "Big Panel" : 57, "Large Poster" : 58, "Big Panel Details" : 59, "Landscape" : 501, "Landscape Single" : 502, "Logos" : 503, "Big List 2" : 504, "Landscape Details" : 505, "Extended List" : 506, "Fan Art" : 507, "Single Poster" : 508, "Panel Square" : 509, "Panel Square Details" : 510, "Thumbs" : 511, "Thumbs Details" : 512, "Poster Row" : 513, "Poster Shift" : 514, "Low LIst" : 515, "Slim List" : 516, "Cards" : 517, "Wide" : 518, "Big Panel Wall" : 519, "Panel Wall" : 520, "Panel Low" : 521, "Right List" : 522, "Netflix" : 523, "Showcase" : 524}
}

View File

@@ -26,10 +26,6 @@ msgctxt "#30003"
msgid "Verify HTTPS Certificate: "
msgstr ""
msgctxt "#30004"
msgid "Log Level: "
msgstr ""
msgctxt "#30005"
msgid "Username: "
msgstr ""
@@ -422,10 +418,6 @@ msgctxt "#30254"
msgid "Show Settings"
msgstr ""
msgctxt "#30255"
msgid "Set Default Views"
msgstr ""
msgctxt "#30256"
msgid "Movies - All"
msgstr ""
@@ -550,6 +542,3 @@ msgctxt "#30286"
msgid "Movies - Unwatched"
msgstr ""
msgctxt "#30287"
msgid "Log Errors and Anonymous Metrics"
msgstr ""

View File

@@ -22,18 +22,18 @@ class ClientInformation():
return client_id
emby_guid_path = xbmc.translatePath("special://temp/embycon_guid").decode('utf-8')
log.info("emby_guid_path: " + emby_guid_path)
log.debug("emby_guid_path: " + emby_guid_path)
guid = xbmcvfs.File(emby_guid_path)
client_id = guid.read()
guid.close()
if not client_id:
client_id = str("%012X" % uuid4())
log.info("Generating a new guid: " + client_id)
log.debug("Generating a new guid: " + client_id)
guid = xbmcvfs.File(emby_guid_path, 'w')
guid.write(client_id)
guid.close()
log.info("emby_guid_path (NEW): " + client_id)
log.debug("emby_guid_path (NEW): " + client_id)
WINDOW.setProperty("client_id", client_id)
return client_id

View File

@@ -23,7 +23,7 @@ class DataManager():
canRefreshNow = False
def __init__(self, *args):
log.info("DataManager __init__")
log.debug("DataManager __init__")
def getCacheValidatorFromData(self, result):
key = 'Items'
@@ -65,10 +65,10 @@ class DataManager():
if use_cache_system == False:
# dont use cache system at all, just get the result and return
log.info("GetContent - Not using cache system")
log.debug("GetContent - Not using cache system")
jsonData = DownloadUtils().downloadUrl(url, suppress=False, popup=1)
result = self.loadJasonData(jsonData)
log.info("Returning Loaded Result")
log.debug("Returning Loaded Result")
return result
# first get the url hash
@@ -83,7 +83,7 @@ class DataManager():
os.makedirs(os.path.join(__addondir__, "cache"))
cacheDataPath = os.path.join(__addondir__, "cache", urlHash)
log.info("Cache_Data_Manager:" + cacheDataPath)
log.debug("Cache_Data_Manager:" + cacheDataPath)
# are we forcing a reload
WINDOW = HomeWindow()
@@ -93,7 +93,7 @@ class DataManager():
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
log.info("Loading Cached File")
log.debug("Loading Cached File")
cachedfie = open(cacheDataPath, 'r')
jsonData = cachedfie.read()
cachedfie.close()
@@ -107,18 +107,18 @@ class DataManager():
actionThread.setCacheData(self)
actionThread.start()
log.info("Returning Cached Result")
log.debug("Returning Cached Result")
return result
else:
# no cache data so load the url and save it
jsonData = DownloadUtils().downloadUrl(url, suppress=False, popup=1)
log.info("Loading URL and saving to cache")
log.debug("Loading URL and saving to cache")
cachedfie = open(cacheDataPath, 'w')
cachedfie.write(jsonData)
cachedfie.close()
result = self.loadJasonData(jsonData)
self.cacheManagerFinished = True
log.info("Returning Loaded Result")
log.debug("Returning Loaded Result")
return result
@@ -133,19 +133,19 @@ class CacheManagerThread(threading.Thread):
def run(self):
log.info("CacheManagerThread Started")
log.debug("CacheManagerThread Started")
cacheValidatorString = self.dataManager.getCacheValidatorFromData(self.dataManager.cacheDataResult)
log.info("Cache Validator String (" + cacheValidatorString + ")")
log.debug("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 + ")")
log.debug("Loaded Validator String (" + loadedValidatorString + ")")
# if they dont match then save the data and trigger a content reload
if (cacheValidatorString != loadedValidatorString):
log.info("CacheManagerThread Saving new cache data and reloading container")
log.debug("CacheManagerThread Saving new cache data and reloading container")
cachedfie = open(self.dataManager.cacheDataPath, 'w')
cachedfie.write(jsonData)
cachedfie.close()
@@ -157,7 +157,7 @@ class CacheManagerThread(threading.Thread):
xbmc.sleep(100)
loops = loops + 1
log.info("Sending container refresh (" + str(loops) + ")")
log.debug("Sending container refresh (" + str(loops) + ")")
xbmc.executebuiltin("Container.Refresh")
log.info("CacheManagerThread Exited")
log.debug("CacheManagerThread Exited")

View File

@@ -129,7 +129,7 @@ class DownloadUtils():
userid = WINDOW.getProperty("userid")
if (userid != None and userid != ""):
log.info("EmbyCon DownloadUtils -> Returning saved UserID : " + userid)
log.debug("EmbyCon DownloadUtils -> Returning saved UserID : " + userid)
return userid
settings = xbmcaddon.Addon('plugin.video.embycon')
@@ -137,7 +137,7 @@ class DownloadUtils():
if not userName:
return ""
log.info("Looking for user name: " + userName)
log.debug("Looking for user name: " + userName)
jsonData = None
try:
@@ -147,30 +147,30 @@ class DownloadUtils():
log.error(error)
return ""
log.info("GETUSER_JSONDATA_01:" + str(jsonData))
log.debug("GETUSER_JSONDATA_01:" + str(jsonData))
result = []
try:
result = json.loads(jsonData)
except Exception, e:
log.info("jsonload : " + str(e) + " (" + jsonData + ")")
log.debug("jsonload : " + str(e) + " (" + jsonData + ")")
return ""
if result is None:
return ""
log.info("GETUSER_JSONDATA_02:" + str(result))
log.debug("GETUSER_JSONDATA_02:" + str(result))
userid = ""
secure = False
for user in result:
if (user.get("Name") == userName):
userid = user.get("Id")
log.info("Username Found:" + user.get("Name"))
log.debug("Username Found:" + user.get("Name"))
if (user.get("HasPassword") == True):
secure = True
log.info("Username Is Secure (HasPassword=True)")
log.debug("Username Is Secure (HasPassword=True)")
break
if (secure) or (not userid):
@@ -184,7 +184,7 @@ class DownloadUtils():
if userid == "":
xbmcgui.Dialog().ok(self.addon_name, i18n('username_not_found'))
log.info("userid : " + userid)
log.debug("userid : " + userid)
WINDOW.setProperty("userid", userid)
@@ -196,7 +196,7 @@ class DownloadUtils():
token = WINDOW.getProperty("AccessToken")
if (token != None and token != ""):
log.info("EmbyCon DownloadUtils -> Returning saved AccessToken : " + token)
log.debug("EmbyCon DownloadUtils -> Returning saved AccessToken : " + token)
return token
settings = xbmcaddon.Addon('plugin.video.embycon')
@@ -233,12 +233,12 @@ class DownloadUtils():
pass
if (accessToken != None):
log.info("User Authenticated : " + accessToken)
log.debug("User Authenticated : " + accessToken)
WINDOW.setProperty("AccessToken", accessToken)
WINDOW.setProperty("userid", userid)
return accessToken
else:
log.info("User NOT Authenticated")
log.debug("User NOT Authenticated")
WINDOW.setProperty("AccessToken", "")
WINDOW.setProperty("userid", "")
return ""
@@ -272,11 +272,11 @@ class DownloadUtils():
if (authToken != ""):
headers["X-MediaBrowser-Token"] = authToken
log.info("EmbyCon Authentication Header : " + str(headers))
log.debug("EmbyCon Authentication Header : " + str(headers))
return headers
def downloadUrl(self, url, suppress=False, postBody=None, method="GET", popup=0, authenticate=True):
log.info("downloadUrl")
log.debug("downloadUrl")
settings = xbmcaddon.Addon(id='plugin.video.embycon')
log.debug(url)
@@ -303,7 +303,7 @@ class DownloadUtils():
server = url.split('/')[serversplit]
urlPath = "/" + "/".join(url.split('/')[urlsplit:])
log.info("DOWNLOAD_URL = " + url)
log.debug("DOWNLOAD_URL = " + url)
log.debug("server = " + str(server))
log.debug("urlPath = " + str(urlPath))
@@ -329,7 +329,7 @@ class DownloadUtils():
conn = httplib.HTTPConnection(server, timeout=40)
head = self.getAuthHeader(authenticate)
log.info("HEADERS : " + str(head))
log.debug("HEADERS : " + str(head))
if (postBody != None):
if isinstance(postBody, dict):
@@ -339,9 +339,9 @@ class DownloadUtils():
content_type = "application/x-www-form-urlencoded"
head["Content-Type"] = content_type
log.info("Content-Type : " + content_type)
log.debug("Content-Type : " + content_type)
log.info("POST DATA : " + postBody)
log.debug("POST DATA : " + postBody)
conn.request(method=method, url=urlPath, body=postBody, headers=head)
else:
conn.request(method=method, url=urlPath, headers=head)

View File

@@ -19,7 +19,6 @@ from utils import getDetailsString, getArt
from kodi_utils import HomeWindow
from clientinfo import ClientInformation
from datamanager import DataManager
from views import DefaultViews, loadSkinDefaults
from server_detect import checkServer
from simple_logging import SimpleLogging
from menu_functions import displaySections, showMovieAlphaList, showGenreList, showWidgets, showSearch
@@ -40,7 +39,7 @@ dataManager = DataManager()
def mainEntryPoint():
log.info("===== EmbyCon START =====")
log.debug("===== EmbyCon START =====")
settings = xbmcaddon.Addon(id='plugin.video.embycon')
profile_code = settings.getSetting('profile') == "true"
@@ -52,11 +51,11 @@ def mainEntryPoint():
pr.enable()
ADDON_VERSION = ClientInformation().getVersion()
log.info("Running Python: " + str(sys.version_info))
log.info("Running EmbyCon: " + str(ADDON_VERSION))
log.info("Kodi BuildVersion: " + xbmc.getInfoLabel("System.BuildVersion"))
log.info("Kodi Version: " + str(kodi_version))
log.info("Script argument data: " + str(sys.argv))
log.debug("Running Python: " + str(sys.version_info))
log.debug("Running EmbyCon: " + str(ADDON_VERSION))
log.debug("Kodi BuildVersion: " + xbmc.getInfoLabel("System.BuildVersion"))
log.debug("Kodi Version: " + str(kodi_version))
log.debug("Script argument data: " + str(sys.argv))
try:
params = get_params(sys.argv[2])
@@ -66,7 +65,7 @@ def mainEntryPoint():
if (len(params) == 0):
home_window = HomeWindow()
windowParams = home_window.getProperty("Params")
log.info("windowParams : " + windowParams)
log.debug("windowParams : " + windowParams)
# home_window.clearProperty("Params")
if (windowParams):
try:
@@ -74,7 +73,7 @@ def mainEntryPoint():
except:
params = {}
log.info("Script params = " + str(params))
log.debug("Script params = " + str(params))
param_url = params.get('url', None)
@@ -115,14 +114,12 @@ def mainEntryPoint():
__addon__.openSettings()
WINDOW = xbmcgui.getCurrentWindowId()
if WINDOW == 10000:
log.info("Currently in home - refreshing to allow new settings to be taken")
log.debug("Currently in home - refreshing to allow new settings to be taken")
xbmc.executebuiltin("ActivateWindow(Home)")
elif sys.argv[1] == "refresh":
home_window = HomeWindow()
home_window.setProperty("force_data_reload", "true")
xbmc.executebuiltin("Container.Refresh")
elif mode == "SET_DEFAULT_VIEWS":
showSetViews()
elif mode == "WIDGET_CONTENT":
getWigetContent(int(sys.argv[1]), params)
elif mode == "PARENT_CONTENT":
@@ -164,8 +161,8 @@ def mainEntryPoint():
pluginhandle = int(sys.argv[1])
log.info("EmbyCon -> Mode: " + str(mode))
log.info("EmbyCon -> URL: " + str(param_url))
log.debug("EmbyCon -> Mode: " + str(mode))
log.debug("EmbyCon -> URL: " + str(param_url))
# Run a function based on the mode variable that was passed in the URL
# if ( mode == None or param_url == None or len(param_url) < 1 ):
@@ -211,11 +208,11 @@ def mainEntryPoint():
f.close()
log.info("===== EmbyCon FINISHED =====")
log.debug("===== EmbyCon FINISHED =====")
def markWatched(item_id):
log.info("Mark Item Watched : " + item_id)
log.debug("Mark Item Watched : " + item_id)
url = "{server}/emby/Users/{userid}/PlayedItems/" + item_id
downloadUtils.downloadUrl(url, postBody="", method="POST")
home_window = HomeWindow()
@@ -224,7 +221,7 @@ def markWatched(item_id):
def markUnwatched(item_id):
log.info("Mark Item UnWatched : " + item_id)
log.debug("Mark Item UnWatched : " + item_id)
url = "{server}/emby/Users/{userid}/PlayedItems/" + item_id
downloadUtils.downloadUrl(url, method="DELETE")
home_window = HomeWindow()
@@ -233,7 +230,7 @@ def markUnwatched(item_id):
def markFavorite(item_id):
log.info("Add item to favourites : " + item_id)
log.debug("Add item to favourites : " + item_id)
url = "{server}/emby/Users/{userid}/FavoriteItems/" + item_id
downloadUtils.downloadUrl(url, postBody="", method="POST")
home_window = HomeWindow()
@@ -242,7 +239,7 @@ def markFavorite(item_id):
def unmarkFavorite(item_id):
log.info("Remove item from favourites : " + item_id)
log.debug("Remove item from favourites : " + item_id)
url = "{server}/emby/Users/{userid}/FavoriteItems/" + item_id
downloadUtils.downloadUrl(url, method="DELETE")
home_window = HomeWindow()
@@ -253,7 +250,7 @@ def unmarkFavorite(item_id):
def delete(item_id):
return_value = xbmcgui.Dialog().yesno(i18n('confirm_file_delete'), i18n('file_delete_confirm'))
if return_value:
log.info('Deleting Item : ' + item_id)
log.debug('Deleting Item : ' + item_id)
url = '{server}/emby/Items/' + item_id
progress = xbmcgui.DialogProgress()
progress.create(i18n('deleting'), i18n('waiting_server_delete'))
@@ -326,7 +323,7 @@ def addGUIItem(url, details, extraData, display_options, folder=True):
details['title'] = listItemName
if kodi_version > 17:
list_item = xbmcgui.ListItem(listItemName, iconImage=thumbPath, thumbnailImage=thumbPath, offscreen=True)
list_item = xbmcgui.ListItem(listItemName, offscreen=True)
else:
list_item = xbmcgui.ListItem(listItemName, iconImage=thumbPath, thumbnailImage=thumbPath)
@@ -502,45 +499,29 @@ def get_params(paramstring):
def setSort(pluginhandle, viewType):
defaultData = loadSkinDefaults()
# set the default sort order
defaultSortData = defaultData.get("sort", {})
sortName = defaultSortData.get(viewType)
log.info("SETTING_SORT : " + str(viewType) + " : " + str(sortName))
if sortName == "title":
xbmcplugin.addSortMethod(pluginhandle, xbmcplugin.SORT_METHOD_VIDEO_SORT_TITLE_IGNORE_THE)
elif sortName == "date":
log.debug("SETTING_SORT for media type: " + str(viewType))
if viewType == "BoxSets":
xbmcplugin.addSortMethod(pluginhandle, xbmcplugin.SORT_METHOD_VIDEO_YEAR)
xbmcplugin.addSortMethod(pluginhandle, xbmcplugin.SORT_METHOD_VIDEO_SORT_TITLE_IGNORE_THE)
else:
xbmcplugin.addSortMethod(pluginhandle, xbmcplugin.SORT_METHOD_VIDEO_SORT_TITLE_IGNORE_THE)
xbmcplugin.addSortMethod(pluginhandle, xbmcplugin.SORT_METHOD_VIDEO_YEAR)
xbmcplugin.addSortMethod(pluginhandle, xbmcplugin.SORT_METHOD_GENRE)
xbmcplugin.addSortMethod(pluginhandle, xbmcplugin.SORT_METHOD_UNSORTED)
xbmcplugin.addSortMethod(pluginhandle, xbmcplugin.SORT_METHOD_NONE)
xbmcplugin.addSortMethod(pluginhandle, xbmcplugin.SORT_METHOD_VIDEO_RATING)
xbmcplugin.addSortMethod(pluginhandle, xbmcplugin.SORT_METHOD_LABEL)
def setView(viewType):
defaultData = loadSkinDefaults()
defaultViewData = defaultData.get("view", {})
viewNum = defaultViewData.get(viewType)
log.info("SETTING_VIEW : " + str(viewType) + " : " + str(viewNum))
if viewNum is not None and viewNum != -1:
xbmc.executebuiltin("Container.SetViewMode(%s)" % int(viewNum))
xbmcplugin.addSortMethod(pluginhandle, xbmcplugin.SORT_METHOD_GENRE)
xbmcplugin.addSortMethod(pluginhandle, xbmcplugin.SORT_METHOD_UNSORTED)
xbmcplugin.addSortMethod(pluginhandle, xbmcplugin.SORT_METHOD_NONE)
xbmcplugin.addSortMethod(pluginhandle, xbmcplugin.SORT_METHOD_VIDEO_RATING)
xbmcplugin.addSortMethod(pluginhandle, xbmcplugin.SORT_METHOD_LABEL)
def getContent(url, params):
log.info("== ENTER: getContent ==")
log.debug("== ENTER: getContent ==")
media_type = params.get("media_type", None)
if not media_type:
xbmcgui.Dialog().ok(i18n('error'), i18n('no_media_type'))
log.info("URL: " + str(url))
log.info("MediaType: " + str(media_type))
log.debug("URL: " + str(url))
log.debug("MediaType: " + str(media_type))
pluginhandle = int(sys.argv[1])
settings = xbmcaddon.Addon(id='plugin.video.embycon')
@@ -562,7 +543,7 @@ def getContent(url, params):
elif media_type == "season" or media_type == "episodes":
viewType = "Episodes"
xbmcplugin.setContent(pluginhandle, 'episodes')
log.info("ViewType: " + viewType)
log.debug("ViewType: " + viewType)
setSort(pluginhandle, viewType)
@@ -586,9 +567,6 @@ def getContent(url, params):
return
xbmcplugin.addDirectoryItems(pluginhandle, dirItems)
# set the view mode based on what the user wanted for this view type
setView(viewType)
xbmcplugin.endOfDirectory(pluginhandle, cacheToDisc=False)
if (progress != None):
@@ -599,7 +577,7 @@ def getContent(url, params):
def processDirectory(results, progress, params):
log.info("== ENTER: processDirectory ==")
log.debug("== ENTER: processDirectory ==")
settings = xbmcaddon.Addon(id='plugin.video.embycon')
server = downloadUtils.getServer()
@@ -907,17 +885,8 @@ def processDirectory(results, progress, params):
return dirItems
def showSetViews():
log.info("showSetViews Called")
defaultViews = DefaultViews("DefaultViews.xml", __cwd__, "default", "720p")
defaultViews.doModal()
del defaultViews
def getWigetContent(handle, params):
log.info("getWigetContent Called" + str(params))
log.debug("getWigetContent Called" + str(params))
server = downloadUtils.getServer()
type = params.get("type")
@@ -1076,7 +1045,7 @@ def getWigetContent(handle, params):
def showContent(pluginName, handle, params):
log.info("showContent Called: " + str(params))
log.debug("showContent Called: " + str(params))
item_type = params.get("item_type")
@@ -1090,11 +1059,11 @@ def showContent(pluginName, handle, params):
"&IsMissing=False"
"&IncludeItemTypes=" + item_type)
log.info("showContent Content Url : " + str(contentUrl))
log.debug("showContent Content Url : " + str(contentUrl))
getContent(contentUrl, params)
def showParentContent(pluginName, handle, params):
log.info("showParentContent Called: " + str(params))
log.debug("showParentContent Called: " + str(params))
settings = xbmcaddon.Addon(id='plugin.video.embycon')
@@ -1109,7 +1078,7 @@ def showParentContent(pluginName, handle, params):
"&Fields=" + detailsString +
"&format=json")
log.info("showParentContent Content Url : " + str(contentUrl))
log.debug("showParentContent Content Url : " + str(contentUrl))
getContent(contentUrl, params)
def checkService():
@@ -1125,8 +1094,8 @@ def checkService():
sys.exit()
xbmc.sleep(200)
log.info("EmbyCon Service Timestamp: " + timeStamp)
log.info("EmbyCon Current Timestamp: " + str(int(time.time())))
log.debug("EmbyCon Service Timestamp: " + timeStamp)
log.debug("EmbyCon Current Timestamp: " + str(int(time.time())))
if ((int(timeStamp) + 240) < int(time.time())):
log.error("EmbyCon Service Not Running, time stamp to old, exiting")
@@ -1135,7 +1104,7 @@ def checkService():
def search(handle, params):
log.info('search Called: ' + str(params))
log.debug('search Called: ' + str(params))
item_type = params.get('item_type')
if not item_type:
return
@@ -1164,7 +1133,7 @@ def search(handle, params):
def searchResults(params):
log.info('searchResults Called: ' + str(params))
log.debug('searchResults Called: ' + str(params))
handle = int(sys.argv[1])
query = params.get('query')
@@ -1330,7 +1299,6 @@ def searchResults(params):
list_items.append(item_tuple)
xbmcplugin.addDirectoryItems(handle, list_items)
setView(view_type)
xbmcplugin.endOfDirectory(handle, cacheToDisc=False)
if progress is not None:
@@ -1339,16 +1307,16 @@ def searchResults(params):
def PLAY(params, handle):
log.info("== ENTER: PLAY ==")
log.debug("== ENTER: PLAY ==")
log.info("PLAY ACTION PARAMS: " + str(params))
log.debug("PLAY ACTION PARAMS: " + str(params))
item_id = params.get("item_id")
auto_resume = int(params.get("auto_resume", "-1"))
log.info("AUTO_RESUME: " + str(auto_resume))
log.debug("AUTO_RESUME: " + str(auto_resume))
forceTranscode = params.get("force_transcode", None) is not None
log.info("FORCE_TRANSCODE: " + str(forceTranscode))
log.debug("FORCE_TRANSCODE: " + str(forceTranscode))
# set the current playing item id
# set all the playback info, this will be picked up by the service

View File

@@ -1,245 +0,0 @@
import sys
import os
import traceback
import hashlib
import time
import xbmcaddon
import xbmc
import urllib
import httplib
import ssl
from clientinfo import ClientInformation
from simple_logging import SimpleLogging
log = SimpleLogging(__name__)
# for info on the metrics that can be sent to Google Analytics
# https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#events
logEventHistory = {}
# wrap a function to catch, log and then re throw an exception
def log_error(errors=(Exception, )):
def decorator(func):
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except errors as error:
if not (hasattr(error, 'quiet') and error.quiet):
ga = GoogleAnalytics()
err_strings = ga.formatException()
ga.sendEventData("Exception", err_strings[0], err_strings[1], True)
log.error(error)
log.error("log_error: %s \n args: %s \n kwargs: %s" % (func.__name__, args, kwargs))
raise
return wrapper
return decorator
# main GA class
class GoogleAnalytics:
testing = False
enabled = True
def __init__(self):
settings = xbmcaddon.Addon('plugin.video.embycon')
client_info = ClientInformation()
self.version = client_info.getVersion()
self.device_id = client_info.getDeviceId()
self.enabled = settings.getSetting("metricLogging") == "true"
# user agent string, used for OS and Kodi version identification
kodi_ver = xbmc.getInfoLabel("System.BuildVersion")
if not kodi_ver:
kodi_ver = "na"
kodi_ver = kodi_ver.strip()
if kodi_ver.find(" ") > 0:
kodi_ver = kodi_ver[0:kodi_ver.find(" ")]
self.userAgent = "Kodi/" + kodi_ver + " (" + self.getUserAgentOS() + ")"
# Use set user name
self.user_name = settings.getSetting('username') or 'None'
# use md5 for client and user for analytics
self.device_id = hashlib.md5(self.device_id).hexdigest()
self.user_name = hashlib.md5(self.user_name).hexdigest()
# resolution
self.screen_mode = xbmc.getInfoLabel("System.ScreenMode")
self.screen_height = xbmc.getInfoLabel("System.ScreenHeight")
self.screen_width = xbmc.getInfoLabel("System.ScreenWidth")
self.lang = xbmc.getInfoLabel("System.Language")
def getUserAgentOS(self):
if xbmc.getCondVisibility('system.platform.osx'):
return "Mac OS X"
elif xbmc.getCondVisibility('system.platform.ios'):
return "iOS"
elif xbmc.getCondVisibility('system.platform.windows'):
return "Windows NT"
elif xbmc.getCondVisibility('system.platform.android'):
return "Android"
elif xbmc.getCondVisibility('system.platform.linux.raspberrypi'):
return "Linux Rpi"
elif xbmc.getCondVisibility('system.platform.linux'):
return "Linux"
else:
return "Other"
def formatException(self):
stack = traceback.extract_stack()
exc_type, exc_obj, exc_tb = sys.exc_info()
tb = traceback.extract_tb(exc_tb)
full_tb = stack[:-1] + tb
#log.error(str(full_tb))
# get last stack frame
latestStackFrame = None
if len(tb) > 0:
latestStackFrame = tb[-1]
#log.error(str(tb))
fileStackTrace = ""
try:
# get files from stack
stackFileList = []
for frame in full_tb:
#log.error(str(frame))
frameFile = (os.path.split(frame[0])[1])[:-3]
frameLine = frame[1]
if len(stackFileList) == 0 or stackFileList[-1][0] != frameFile:
stackFileList.append([frameFile, [str(frameLine)]])
else:
file = stackFileList[-1][0]
lines = stackFileList[-1][1]
lines.append(str(frameLine))
stackFileList[-1] = [file, lines]
#log.error(str(stackFileList))
for item in stackFileList:
lines = ",".join(item[1])
fileStackTrace += item[0] + "," + lines + ":"
#log.error(str(fileStackTrace))
except Exception as e:
fileStackTrace = None
log.error(e)
errorType = "NA"
errorFile = "NA"
if latestStackFrame is not None:
if fileStackTrace is None:
fileStackTrace = os.path.split(latestStackFrame[0])[1] + ":" + str(latestStackFrame[1])
codeLine = "NA"
if(len(latestStackFrame) > 3 and latestStackFrame[3] != None):
codeLine = latestStackFrame[3].strip()
errorFile = "%s(%s)(%s)" % (fileStackTrace, exc_obj.message, codeLine)
errorFile = errorFile[0:499]
errorType = "%s" % (exc_type.__name__)
#log.error(errorType + " - " + errorFile)
del(exc_type, exc_obj, exc_tb)
return errorType, errorFile
def getBaseData(self):
# all the data we can send to Google Analytics
data = {}
data['v'] = '1'
data['tid'] = 'UA-101964432-1' # tracking id
data['ds'] = 'plugin' # data source
data['an'] = 'EmbyCon' # App Name
data['aid'] = '1' # App ID
data['av'] = self.version # App Version
#data['aiid'] = '1.1' # App installer ID
data['cid'] = self.device_id # Client ID
#data['uid'] = self.user_name # User ID
data['ua'] = self.userAgent # user agent string
# add width and height, only add if full screen
if self.screen_mode.lower().find("window") == -1:
data['sr'] = str(self.screen_width) + "x" + str(self.screen_height)
data["ul"] = self.lang
return data
def sendScreenView(self, name):
data = self.getBaseData()
data['t'] = 'screenview' # action type
data['cd'] = name
self.sendData(data)
def sendEventData(self, eventCategory, eventAction, eventLabel=None, throttle=False):
# if throttling is enabled then only log the same event every 5 min
if throttle:
throttleKey = eventCategory + "-" + eventAction + "-" + str(eventLabel)
lastLogged = logEventHistory.get(throttleKey)
if lastLogged != None:
timeSinceLastLog = time.time() - lastLogged
if timeSinceLastLog < 300 :
log.info("SKIPPING_LOG_EVENT : " + str(timeSinceLastLog) + " " + throttleKey)
return
logEventHistory[throttleKey] = time.time()
data = self.getBaseData()
data['t'] = 'event' # action type
data['ec'] = eventCategory # Event Category
data['ea'] = eventAction # Event Action
if eventLabel is not None :
data['el'] = eventLabel # Event Label
self.sendData(data)
def sendData(self, data):
if not self.enabled:
return
if self.testing:
log.info("GA: " + str(data))
postData = ""
for key in data:
postData = postData + key + "=" + urllib.quote(data[key]) + "&"
server = "www.google-analytics.com:443"
if self.testing:
url_path = "/debug/collect"
else:
url_path = "/collect"
ret_data = None
try:
conn = httplib.HTTPSConnection(server, timeout=40, context=ssl._create_unverified_context())
head = {}
head["Content-Type"] = "application/x-www-form-urlencoded"
conn.request(method="POST", url=url_path, body=postData, headers=head)
data = conn.getresponse()
if int(data.status) == 200:
ret_data = data.read()
except Exception as error:
log.error("Error sending GA data: " + str(error))
if self.testing and ret_data is not None:
log.info("GA: " + ret_data.encode('utf-8'))

View File

@@ -1,6 +1,7 @@
import xbmc
import xbmcgui
import xbmcplugin
import xbmcaddon
import sys
import json
@@ -8,7 +9,7 @@ import json
from simple_logging import SimpleLogging
log = SimpleLogging(__name__)
addon = xbmcaddon.Addon()
class HomeWindow():
"""
@@ -39,7 +40,7 @@ class HomeWindow():
def addMenuDirectoryItem(label, path, folder=True, thumbnail=None):
li = xbmcgui.ListItem(label, path=path)
if thumbnail is None:
thumbnail = "special://home/addons/plugin.video.embycon/icon.png"
thumbnail = addon.getAddonInfo('icon')
li.setIconImage(thumbnail)
li.setThumbnailImage(thumbnail)
xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=path, listitem=li, isFolder=folder)
@@ -56,7 +57,7 @@ def getKodiVersion():
result = result.get("result")
versionData = result.get("version")
version = float(str(versionData.get("major")) + "." + str(versionData.get("minor")))
log.info("Version : " + str(version) + " - " + str(versionData))
log.debug("Version : " + str(version) + " - " + str(versionData))
except:
version = 0.0
log.error("Version Error : RAW Version Data : " + str(result))

View File

@@ -20,7 +20,7 @@ __addon__ = xbmcaddon.Addon(id='plugin.video.embycon')
def showGenreList():
log.info("== ENTER: showGenreList() ==")
log.debug("== ENTER: showGenreList() ==")
server = downloadUtils.getServer()
if server is None:
@@ -30,7 +30,7 @@ def showGenreList():
try:
jsonData = downloadUtils.downloadUrl("{server}/emby/Genres?SortBy=SortName&SortOrder=Ascending&IncludeTypes=Movie&Recursive=true&UserId={userid}&format=json")
log.info("GENRE_LIST_DATA : " + jsonData)
log.debug("GENRE_LIST_DATA : " + jsonData)
except Exception, msg:
error = "Get connect : " + str(msg)
log.error(error)
@@ -55,14 +55,14 @@ def showGenreList():
url = sys.argv[0] + ("?url=" + urllib.quote(collection['path']) +
"&mode=GET_CONTENT" +
"&media_type=" + collection["media_type"])
log.info("addMenuDirectoryItem: " + collection.get('title', i18n('unknown')) + " " + str(url))
log.debug("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]))
def showMovieAlphaList():
log.info("== ENTER: showMovieAlphaList() ==")
log.debug("== ENTER: showMovieAlphaList() ==")
settings = xbmcaddon.Addon(id='plugin.video.embycon')
server = downloadUtils.getServer()
@@ -101,14 +101,14 @@ def showMovieAlphaList():
for collection in collections:
url = (sys.argv[0] + "?url=" + urllib.quote(collection['path']) +
"&mode=GET_CONTENT&media_type=" + collection["media_type"])
log.info("addMenuDirectoryItem: " + collection.get('title', i18n('unknown')) + " " + str(url))
log.debug("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() ==")
log.debug("== ENTER: displaySections() ==")
xbmcplugin.setContent(int(sys.argv[1]), 'files')
server = downloadUtils.getServer()
@@ -125,7 +125,7 @@ def displaySections():
"&mode=GET_CONTENT&media_type=" + collection["media_type"])
if collection.get("name_format") is not None:
url += "&name_format=" + urllib.quote(collection.get("name_format"))
log.info("addMenuDirectoryItem: " + collection.get('title', i18n('unknown')) + " " + str(url))
log.debug("addMenuDirectoryItem: " + collection.get('title', i18n('unknown')) + " " + str(url))
addMenuDirectoryItem(collection.get('title', i18n('unknown')), url, thumbnail=collection.get("thumbnail"))
addMenuDirectoryItem(i18n('movies_genre'), "plugin://plugin.video.embycon/?mode=MOVIE_GENRA")
@@ -137,7 +137,6 @@ def displaySections():
addMenuDirectoryItem(i18n('detect_server'), "plugin://plugin.video.embycon/?mode=DETECT_SERVER_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")
if collections:
addMenuDirectoryItem(i18n('widgets'), "plugin://plugin.video.embycon/?mode=WIDGETS")
@@ -146,7 +145,7 @@ def displaySections():
def getCollections(detailsString):
log.info("== ENTER: getCollections ==")
log.debug("== ENTER: getCollections ==")
server = downloadUtils.getServer()
if server is None:
@@ -155,7 +154,7 @@ def getCollections(detailsString):
userid = downloadUtils.getUserId()
if userid == None or len(userid) == 0:
log.info("No userid so returning []")
log.debug("No userid so returning []")
return []
try:
@@ -171,7 +170,7 @@ def getCollections(detailsString):
return []
parentid = result.get("Id")
log.info("parentid : " + parentid)
log.debug("parentid : " + parentid)
htmlpath = "{server}/emby/Users/{userid}/items?ParentId=" + parentid + "&Sortby=SortName&format=json"
jsonData = downloadUtils.downloadUrl(htmlpath)
@@ -189,8 +188,8 @@ def getCollections(detailsString):
item_name = (item.get("Name")).encode('utf-8')
collection_type = item.get('CollectionType', None)
log.info("CollectionType: " + str(collection_type))
log.info("Title: " + item_name)
log.debug("CollectionType: " + str(collection_type))
log.debug("Title: " + item_name)
if collection_type in ["tvshows", "movies", "boxsets"]:
collections.append({

View File

@@ -15,7 +15,6 @@ from utils import PlayUtils, getArt
from kodi_utils import HomeWindow
from translation import i18n
from json_rpc import json_rpc
from ga_client import GoogleAnalytics, log_error
log = SimpleLogging(__name__)
downloadUtils = DownloadUtils()
@@ -27,7 +26,7 @@ def playFile(play_info):
auto_resume = play_info.get("auto_resume")
force_transcode = play_info.get("force_transcode")
log.info("playFile id(%s) resume(%s) force_transcode(%s)" % (id, auto_resume, force_transcode))
log.debug("playFile id(%s) resume(%s) force_transcode(%s)" % (id, auto_resume, force_transcode))
settings = xbmcaddon.Addon('plugin.video.embycon')
addon_path = settings.getAddonInfo('path')
@@ -58,13 +57,13 @@ def playFile(play_info):
resumeDialog.doModal()
resume_result = resumeDialog.getResumeAction()
del resumeDialog
log.info("Resume Dialog Result: " + str(resume_result))
log.debug("Resume Dialog Result: " + str(resume_result))
# check system settings for play action
# if prompt is set ask to set it to auto resume
params = {"setting": "myvideos.selectaction"}
setting_result = json_rpc('Settings.getSettingValue').execute(params)
log.info("Current Setting (myvideos.selectaction): %s" % setting_result)
log.debug("Current Setting (myvideos.selectaction): %s" % setting_result)
current_value = setting_result.get("result", None)
if current_value is not None:
current_value = current_value.get("value", -1)
@@ -73,7 +72,7 @@ def playFile(play_info):
if return_value:
params = {"setting": "myvideos.selectaction", "value": 2}
json_rpc_result = json_rpc('Settings.setSettingValue').execute(params)
log.info("Save Setting (myvideos.selectaction): %s" % json_rpc_result)
log.debug("Save Setting (myvideos.selectaction): %s" % json_rpc_result)
if resume_result == 1:
seekTime = 0
@@ -92,7 +91,7 @@ def playFile(play_info):
if not playurl:
playurl = PlayUtils().getPlayUrl(id, result, force_transcode)
log.info("Play URL: " + playurl + " ListItem Properties: " + str(listitem_props))
log.debug("Play URL: " + playurl + " ListItem Properties: " + str(listitem_props))
playback_type_string = "DirectPlay"
if playback_type == "2" or force_transcode:
@@ -118,34 +117,26 @@ def playFile(play_info):
playlist.add(playurl, list_item)
xbmc.Player().play(playlist)
item_type = result.get('Type', 'na')
if seekTime == 0:
return
try:
if seekTime == 0:
count = 0
while not xbmc.Player().isPlaying():
log.debug("Not playing yet...sleep for 1 sec")
count = count + 1
if count >= 10:
return
else:
time.sleep(1)
count = 0
while not xbmc.Player().isPlaying():
log.info("Not playing yet...sleep for 1 sec")
count = count + 1
if count >= 10:
return
else:
time.sleep(1)
seekTime = seekTime - jump_back_amount
seekTime = seekTime - jump_back_amount
while xbmc.Player().getTime() < (seekTime - 5):
# xbmc.Player().pause()
xbmc.sleep(100)
xbmc.Player().seekTime(seekTime)
xbmc.sleep(100)
# xbmc.Player().play()
finally:
ga = GoogleAnalytics()
ga.sendEventData("PlayAction", item_type, playback_type_string)
ga.sendScreenView(item_type)
while xbmc.Player().getTime() < (seekTime - 5):
# xbmc.Player().pause()
xbmc.sleep(100)
xbmc.Player().seekTime(seekTime)
xbmc.sleep(100)
# xbmc.Player().play()
def setListItemProps(id, listItem, result, server, extra_props):
# set up item and item info

View File

@@ -14,7 +14,7 @@ class ResumeDialog(xbmcgui.WindowXMLDialog):
def __init__(self, *args, **kwargs):
xbmcgui.WindowXMLDialog.__init__(self, *args, **kwargs)
log.info("ResumeDialog INITIALISED")
log.debug("ResumeDialog INITIALISED")
def onInit(self):
self.action_exitkeys_id = [10, 13]

View File

@@ -90,7 +90,7 @@ def checkServer(force=False, change_user=False, notify=False):
server_address = url_bits.hostname
server_port = str(url_bits.port)
server_protocol = url_bits.scheme
log.info("Detected server info " + server_protocol + " - " + server_address + " - " + server_port)
log.debug("Detected server info " + server_protocol + " - " + server_address + " - " + server_port)
# save the server info
settings.setSetting("port", server_port)
@@ -111,7 +111,7 @@ def checkServer(force=False, change_user=False, notify=False):
# if asked or we have no current user then show user selection screen
if change_user or len(current_username) == 0:
# get a list of users
log.info("Getting user list")
log.debug("Getting user list")
jsonData = downloadUtils.downloadUrl(serverUrl + "/emby/Users/Public?format=json", authenticate=False)
log.debug("jsonData : " + str(jsonData))

View File

@@ -1,39 +0,0 @@
import json
from kodi_utils import HomeWindow
from downloadutils import DownloadUtils
from simple_logging import SimpleLogging
log = SimpleLogging(__name__)
def getServerId():
home_screen = HomeWindow()
server_id = home_screen.getProperty("server_id")
if server_id:
log.info("Server ID from stored value: " + server_id)
return server_id
downloadUtils = DownloadUtils()
try:
url = "{server}/emby/system/info/public"
jsonData = downloadUtils.downloadUrl(url, suppress=True, authenticate=False)
result = json.loads(jsonData)
if result is not None and result.get("Id") is not None:
server_id = result.get("Id")
log.info("Server ID from server request: " + server_id)
home_screen.setProperty("server_id", server_id)
return server_id
else:
return None
except Exception as error:
log.info("Could not get Server ID: " + str(error))
return None

View File

@@ -10,7 +10,7 @@ from simple_logging import SimpleLogging
log = SimpleLogging(__name__)
def showServerSessions():
log.info("showServerSessions Called")
log.debug("showServerSessions Called")
handle = int(sys.argv[1])
downloadUtils = DownloadUtils()

View File

@@ -2,45 +2,38 @@
import xbmc
import xbmcaddon
from json_rpc import json_rpc
class SimpleLogging():
level = 0
name = ""
enable_logging = False
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 = prefix + '.' + name
def getLevel(self):
return self.level
params = {"setting": "debug.showloginfo"}
setting_result = json_rpc('Settings.getSettingValue').execute(params)
current_value = setting_result.get("result", None)
if current_value is not None:
self.enable_logging = current_value.get("value", False)
#xbmc.log("LOGGING_ENABLED %s: %s" % (self.name, str(self.enable_logging)), level=xbmc.LOGDEBUG)
def __str__(self):
return "LogLevel: " + str(self.level)
return "LoggingEnabled: " + str(self.enable_logging)
def error(self, msg):
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):
try:
xbmc.log(self.format(msg, "INFO"), level=xbmc.LOGNOTICE)
except UnicodeEncodeError:
xbmc.log(self.format(msg, "INFO").encode('utf-8'), level=xbmc.LOGNOTICE)
try:
xbmc.log(self.format(msg, "ERROR"), level=xbmc.LOGERROR)
except UnicodeEncodeError:
xbmc.log(self.format(msg, "ERROR").encode('utf-8'), level=xbmc.LOGERROR)
def debug(self, msg):
if (self.level >= 2):
if (self.enable_logging):
try:
xbmc.log(self.format(msg, "DEBUG"), level=xbmc.LOGNOTICE)
xbmc.log(self.format(msg, "DEBUG"), level=xbmc.LOGDEBUG)
except UnicodeEncodeError:
xbmc.log(self.format(msg, "DEBUG").encode('utf-8'), level=xbmc.LOGNOTICE)
xbmc.log(self.format(msg, "DEBUG").encode('utf-8'), level=xbmc.LOGDEBUG)
def format(self, msg, levelValue):
return self.name + "(" + str(levelValue) + ") -> " + msg

View File

@@ -62,7 +62,6 @@ STRINGS = {
'movies_az': 30252,
'change_user': 30253,
'show_settings': 30254,
'set_default_views': 30255,
'movies_all': 30256,
'movies_recently_added': 30257,
'movies_in_progress': 30258,

View File

@@ -15,20 +15,20 @@ log = SimpleLogging(__name__)
###########################################################################
class PlayUtils():
def getPlayUrl(self, id, result, force_transcode):
log.info("getPlayUrl")
log.debug("getPlayUrl")
addonSettings = xbmcaddon.Addon(id='plugin.video.embycon')
playback_type = addonSettings.getSetting("playback_type")
server = downloadUtils.getServer()
log.info("playback_type: " + playback_type)
log.debug("playback_type: " + playback_type)
if force_transcode:
log.info("playback_type: FORCED_TRANSCODE")
log.debug("playback_type: FORCED_TRANSCODE")
playurl = None
# transcode
if playback_type == "2" or force_transcode:
playback_bitrate = addonSettings.getSetting("playback_bitrate")
log.info("playback_bitrate: " + playback_bitrate)
log.debug("playback_bitrate: " + playback_bitrate)
width_options = ["640", "720", "1024", "1280", "1440", "1600", "1920", "2600", "4096"]
playback_max_width = width_options[int(addonSettings.getSetting("playback_max_width"))]
@@ -77,7 +77,7 @@ class PlayUtils():
user_token = downloadUtils.authenticate()
playurl = playurl + "&api_key=" + user_token
log.info("Playback URL: " + playurl)
log.debug("Playback URL: " + playurl)
return playurl.encode('utf-8')
def getStrmDetails(self, result):
@@ -101,7 +101,7 @@ class PlayUtils():
elif line != '':
playurl = line
log.info("Playback URL: " + playurl + " ListItem Properties: " + str(listitem_props))
log.debug("Playback URL: " + playurl + " ListItem Properties: " + str(listitem_props))
return playurl, listitem_props

View File

@@ -1,195 +0,0 @@
# Gnu General Public License - see LICENSE.TXT
import os
import xbmc
import xbmcgui
import xbmcaddon
import json
from simple_logging import SimpleLogging
from translation import i18n
log = SimpleLogging(__name__)
__addon__ = xbmcaddon.Addon(id='plugin.video.embycon')
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'))
view_list_path = os.path.join(__addondir__, "default_views.json")
if os.path.exists(view_list_path):
dataFile = open(view_list_path, 'r')
jsonData = dataFile.read()
dataFile.close()
defaultData = json.loads(jsonData)
return defaultData
class DefaultViews(xbmcgui.WindowXMLDialog):
viewData = {}
sortData = {"Title": "title", "Date": "date"}
defaultView = {}
defaultSort = {}
def __init__(self, *args, **kwargs):
xbmcgui.WindowXMLDialog.__init__(self, *args, **kwargs)
log.info("WINDOW INITIALISED")
def onInit(self):
self.action_exitkeys_id = [10, 13]
# load skin views
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)
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))
if skin_views is None:
xbmcgui.Dialog().notification(__addon__.getAddonInfo('name'), i18n('skin_not_supported') % skin_used, icon='special://home/addons/plugin.video.embycon/icon.png')
self.close()
return
self.viewData = skin_views
# load current default views
savedData = loadSkinDefaults()
self.defaultView = savedData.get("view", {})
self.defaultSort = savedData.get("sort", {})
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"))
self.getControl(3010).setLabel(name)
name = self.getViewNameById(self.defaultView.get("BoxSets"))
self.getControl(3011).setLabel(name)
name = self.getViewNameById(self.defaultView.get("Series"))
self.getControl(3012).setLabel(name)
name = self.getViewNameById(self.defaultView.get("Seasons"))
self.getControl(3013).setLabel(name)
name = self.getViewNameById(self.defaultView.get("Episodes"))
self.getControl(3014).setLabel(name)
name = self.getSortNameById(self.defaultSort.get("Movies"))
self.getControl(3050).setLabel(name)
name = self.getSortNameById(self.defaultSort.get("BoxSets"))
self.getControl(3051).setLabel(name)
name = self.getSortNameById(self.defaultSort.get("Series"))
self.getControl(3052).setLabel(name)
name = self.getSortNameById(self.defaultSort.get("Seasons"))
self.getControl(3053).setLabel(name)
name = self.getSortNameById(self.defaultSort.get("Episodes"))
self.getControl(3054).setLabel(name)
def onFocus(self, controlId):
pass
def doAction(self, actionID):
pass
def getSortNameById(self, sortId):
if (sortId == None):
return "None"
for name, id in self.sortData.iteritems():
if id == sortId:
return name
return "None"
def getViewNameById(self, viewId):
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):
return keys[0]
index = keys.index(current)
if (index > -1 and index < len(keys) - 1):
return keys[index + 1]
else:
return keys[0]
def getNextSortName(self, current):
keys = list(self.sortData.keys())
if (current not in keys):
return keys[0]
index = keys.index(current)
if (index > -1 and index < len(keys) - 1):
return keys[index + 1]
else:
return keys[0]
def onClick(self, controlID):
if controlID >= 3010 and controlID <= 3014:
control = self.getControl(controlID)
control.setLabel(self.getNextViewName(control.getLabel()))
elif controlID >= 3050 and controlID <= 3054:
control = self.getControl(controlID)
control.setLabel(self.getNextSortName(control.getLabel()))
elif controlID == 3110:
self.setViewId("Movies", 3010)
self.setViewId("BoxSets", 3011)
self.setViewId("Series", 3012)
self.setViewId("Seasons", 3013)
self.setViewId("Episodes", 3014)
self.setSortId("Movies", 3050)
self.setSortId("BoxSets", 3051)
self.setSortId("Series", 3052)
self.setSortId("Seasons", 3053)
self.setSortId("Episodes", 3054)
__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()
self.close()
def setViewId(self, viewName, labelId):
viewId = self.viewData.get(self.getControl(labelId).getLabel())
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):
return
else:
self.defaultSort[sortName] = sortId

View File

@@ -49,9 +49,7 @@
<setting id="episode_name_format" type="text" default="{SeriesName} - s{SeasonIndex}e{EpisodeIndex} - {ItemName}" label="30019" />
</category>
<category label="30022"> <!-- Advanced -->
<setting id="logLevel" type="enum" label="30004" values="None|Info|Debug" default="0" />
<setting id="profile" type="bool" label="30010" default="false" visible="true" enable="true" />
<setting id="cacheEmbyData" type="bool" label="30138" default="false" visible="true" enable="true" />
<setting id="metricLogging" type="bool" label="30287" default="true" visible="true" enable="true" />
</category>
</settings>

View File

@@ -1,232 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<window id="3301" type="dialog">
<defaultcontrol always="true">3010</defaultcontrol>
<zorder>2</zorder>
<coordinates>
<system>1</system>
<left>315</left>
<top>50</top>
</coordinates>
<include>dialogeffect</include>
<controls>
<control type="image">
<left>0</left>
<top>0</top>
<width>650</width>
<height>500</height>
<texture border="40">bg.png</texture>
</control>
<control type="label" id="3020">
<left>150</left>
<top>45</top>
<width>380</width>
<height>40</height>
<font>font16</font>
<label></label>
<align>left</align>
<textcolor>blue</textcolor>
</control>
<control type="label" id="3019">
<left>400</left>
<top>45</top>
<width>380</width>
<height>40</height>
<font>font16</font>
<label></label>
<align>left</align>
<textcolor>blue</textcolor>
</control>
<control type="label" id="3021">
<left>30</left>
<top>100</top>
<width>120</width>
<height>40</height>
<font>font14</font>
<label></label>
</control>
<control type="button" id="3010">
<texturenofocus border="1" colordiffuse="ff161616">white.png</texturenofocus>
<texturefocus border="1" colordiffuse="ff525252">white.png</texturefocus>
<left>150</left>
<top>100</top>
<width>200</width>
<height>40</height>
<label></label>
<onup></onup>
<onright>3050</onright>
<ondown>3011</ondown>
<font>font14</font>
</control>
<control type="button" id="3050">
<texturenofocus border="1" colordiffuse="ff161616">white.png</texturenofocus>
<texturefocus border="1" colordiffuse="ff525252">white.png</texturefocus>
<left>400</left>
<top>100</top>
<width>200</width>
<height>40</height>
<label></label>
<onup></onup>
<onleft>3010</onleft>
<ondown>3051</ondown>
<font>font14</font>
</control>
<control type="label" id="3022">
<left>30</left>
<top>160</top>
<width>120</width>
<height>40</height>
<font>font14</font>
<label></label>
</control>
<control type="button" id="3011">
<texturenofocus border="1" colordiffuse="ff161616">white.png</texturenofocus>
<texturefocus border="1" colordiffuse="ff525252">white.png</texturefocus>
<left>150</left>
<top>160</top>
<width>200</width>
<height>40</height>
<label></label>
<onup>3010</onup>
<onright>3051</onright>
<ondown>3012</ondown>
<font>font14</font>
</control>
<control type="button" id="3051">
<texturenofocus border="1" colordiffuse="ff161616">white.png</texturenofocus>
<texturefocus border="1" colordiffuse="ff525252">white.png</texturefocus>
<left>400</left>
<top>160</top>
<width>200</width>
<height>40</height>
<label></label>
<onup>3050</onup>
<onleft>3011</onleft>
<ondown>3052</ondown>
<font>font14</font>
</control>
<control type="label" id="3023">
<left>30</left>
<top>220</top>
<width>120</width>
<height>40</height>
<font>font14</font>
<label></label>
</control>
<control type="button" id="3012">
<texturenofocus border="1" colordiffuse="ff161616">white.png</texturenofocus>
<texturefocus border="1" colordiffuse="ff525252">white.png</texturefocus>
<left>150</left>
<top>220</top>
<width>200</width>
<height>40</height>
<label></label>
<onup>3011</onup>
<onright>3052</onright>
<ondown>3013</ondown>
<font>font14</font>
</control>
<control type="button" id="3052">
<texturenofocus border="1" colordiffuse="ff161616">white.png</texturenofocus>
<texturefocus border="1" colordiffuse="ff525252">white.png</texturefocus>
<left>400</left>
<top>220</top>
<width>200</width>
<height>40</height>
<label></label>
<onup>3051</onup>
<onleft>3012</onleft>
<ondown>3053</ondown>
<font>font14</font>
</control>
<control type="label" id="3024">
<left>30</left>
<top>280</top>
<width>120</width>
<height>40</height>
<font>font14</font>
<label></label>
</control>
<control type="button" id="3013">
<texturenofocus border="1" colordiffuse="ff161616">white.png</texturenofocus>
<texturefocus border="1" colordiffuse="ff525252">white.png</texturefocus>
<left>150</left>
<top>280</top>
<width>200</width>
<height>40</height>
<label></label>
<onup>3012</onup>
<onright>3053</onright>
<ondown>3014</ondown>
<font>font14</font>
</control>
<control type="button" id="3053">
<texturenofocus border="1" colordiffuse="ff161616">white.png</texturenofocus>
<texturefocus border="1" colordiffuse="ff525252">white.png</texturefocus>
<left>400</left>
<top>280</top>
<width>200</width>
<height>40</height>
<label></label>
<onup>3052</onup>
<onleft>3013</onleft>
<ondown>3054</ondown>
<font>font14</font>
</control>
<control type="label" id="3025">
<left>30</left>
<top>340</top>
<width>120</width>
<height>40</height>
<font>font14</font>
<label></label>
</control>
<control type="button" id="3014">
<texturenofocus border="1" colordiffuse="ff161616">white.png</texturenofocus>
<texturefocus border="1" colordiffuse="ff525252">white.png</texturefocus>
<left>150</left>
<top>340</top>
<width>200</width>
<height>40</height>
<label></label>
<onup>3013</onup>
<onright>3054</onright>
<ondown>3110</ondown>
<font>font14</font>
</control>
<control type="button" id="3054">
<texturenofocus border="1" colordiffuse="ff161616">white.png</texturenofocus>
<texturefocus border="1" colordiffuse="ff525252">white.png</texturefocus>
<left>400</left>
<top>340</top>
<width>200</width>
<height>40</height>
<label></label>
<onup>3053</onup>
<onleft>3014</onleft>
<ondown>3110</ondown>
<font>font14</font>
</control>
<control type="button" id="3110">
<texturenofocus border="1" colordiffuse="ff161616">white.png</texturenofocus>
<texturefocus border="1" colordiffuse="ff525252">white.png</texturefocus>
<left>150</left>
<top>400</top>
<width>200</width>
<height>40</height>
<label></label>
<onup>3014</onup>
<ondown></ondown>
<font>font14</font>
</control>
</controls>
</window>

View File

@@ -6,15 +6,12 @@ import xbmcaddon
import xbmcgui
import time
import json
import platform
from resources.lib.downloadutils import DownloadUtils
from resources.lib.server_info import getServerId
from resources.lib.simple_logging import SimpleLogging
from resources.lib.play_utils import playFile
from resources.lib.kodi_utils import HomeWindow
from resources.lib.translation import i18n
from resources.lib.ga_client import GoogleAnalytics, log_error
# clear user and token when logging in
home_window = HomeWindow()
@@ -46,7 +43,7 @@ def sendProgress():
if play_data is None:
return
log.info("Sending Progress Update")
log.debug("Sending Progress Update")
play_time = xbmc.Player().getTime()
play_data["currentPossition"] = play_time
@@ -177,19 +174,19 @@ def stopAll(played_information):
if len(played_information) == 0:
return
log.info("played_information : " + str(played_information))
log.debug("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))
log.debug("item_url : " + item_url)
log.debug("item_data : " + str(data))
current_possition = data.get("currentPossition", 0)
emby_item_id = data.get("item_id")
if hasData(emby_item_id):
log.info("Playback Stopped at: " + str(int(current_possition * 10000000)))
log.debug("Playback Stopped at: " + str(int(current_possition * 10000000)))
url = "{server}/emby/Sessions/Playing/Stopped"
postdata = {
@@ -208,16 +205,15 @@ class Service(xbmc.Player):
played_information = {}
def __init__(self, *args):
log.info("Starting monitor service: " + str(args))
log.debug("Starting monitor service: " + str(args))
self.played_information = {}
@log_error()
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)
log.debug("onPlayBackStarted: " + current_playing_file)
home_window = HomeWindow()
emby_item_id = home_window.getProperty("item_id")
@@ -227,7 +223,7 @@ class Service(xbmc.Player):
if emby_item_id is None or len(emby_item_id) == 0:
return
log.info("Sending Playback Started")
log.debug("Sending Playback Started")
postdata = {
'QueueableMediaTypes': "Video",
'CanSeek': True,
@@ -247,29 +243,26 @@ class Service(xbmc.Player):
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))
log.debug("ADDING_FILE : " + current_playing_file)
log.debug("ADDING_FILE : " + str(self.played_information))
@log_error()
def onPlayBackEnded(self):
# Will be called when kodi stops playing a file
log.info("EmbyCon Service -> onPlayBackEnded")
log.debug("EmbyCon Service -> onPlayBackEnded")
home_window = HomeWindow()
home_window.clearProperty("item_id")
stopAll(self.played_information)
@log_error()
def onPlayBackStopped(self):
# Will be called when user stops kodi playing a file
log.info("onPlayBackStopped")
log.debug("onPlayBackStopped")
home_window = HomeWindow()
home_window.clearProperty("item_id")
stopAll(self.played_information)
@log_error()
def onPlayBackPaused(self):
# Will be called when kodi pauses the video
log.info("onPlayBackPaused")
log.debug("onPlayBackPaused")
current_file = xbmc.Player().getPlayingFile()
play_data = monitor.played_information.get(current_file)
@@ -277,10 +270,9 @@ class Service(xbmc.Player):
play_data['paused'] = True
sendProgress()
@log_error()
def onPlayBackResumed(self):
# Will be called when kodi resumes the video
log.info("onPlayBackResumed")
log.debug("onPlayBackResumed")
current_file = xbmc.Player().getPlayingFile()
play_data = monitor.played_information.get(current_file)
@@ -288,79 +280,40 @@ class Service(xbmc.Player):
play_data['paused'] = False
sendProgress()
@log_error()
def onPlayBackSeek(self, time, seekOffset):
# Will be called when kodi seeks in video
log.info("onPlayBackSeek")
log.debug("onPlayBackSeek")
sendProgress()
monitor = Service()
last_progress_update = time.time()
lastMetricPing = time.time()
lastStartCheck = time.time()
startSent = False
ga = GoogleAnalytics()
try:
ga.sendEventData("Version", "OS", platform.platform())
ga.sendEventData("Version", "Python", platform.python_version())
except Exception as error:
log.error("Exception in sending client meta info: " + str(error))
xbmc_monitor = xbmc.Monitor()
while not xbmc_monitor.abortRequested():
try:
while not xbmc.abortRequested:
home_window = HomeWindow()
home_window = HomeWindow()
if xbmc.Player().isPlaying():
try:
if not startSent and (time.time() - lastStartCheck) > 30:
lastStartCheck = time.time()
server_id = getServerId()
if server_id is not None:
startSent = True
ga = GoogleAnalytics()
ga.sendEventData("Application", "Startup", server_id)
if (time.time() - last_progress_update) > 10:
last_progress_update = time.time()
sendProgress()
except Exception as error:
log.error("Exception in sending start message: " + str(error))
raise
log.error("Exception in Playback Monitor : " + str(error))
if xbmc.Player().isPlaying():
else:
play_data = home_window.getProperty("play_item_message")
if play_data:
home_window.clearProperty("play_item_message")
play_info = json.loads(play_data)
playFile(play_info)
try:
if (time.time() - lastMetricPing) > 300:
lastMetricPing = time.time()
ga = GoogleAnalytics()
ga.sendEventData("PlayAction", "PlayPing")
except Exception, e:
log.error("Exception in sending play ping: " + str(e))
xbmc_monitor.waitForAbort(1)
HomeWindow().setProperty("Service_Timestamp", str(int(time.time())))
try:
if (time.time() - last_progress_update) > 10:
last_progress_update = time.time()
sendProgress()
except Exception as error:
log.error("Exception in Playback Monitor : " + str(error))
else:
play_data = home_window.getProperty("play_item_message")
if play_data:
home_window.clearProperty("play_item_message")
play_info = json.loads(play_data)
playFile(play_info)
xbmc.sleep(1000)
HomeWindow().setProperty("Service_Timestamp", str(int(time.time())))
except Exception as error:
ga = GoogleAnalytics()
err_strings = ga.formatException()
ga.sendEventData("Exception", err_strings[0], err_strings[1])
log.error(str(error))
log.error(str(err_strings))
raise
# clear user and token when loggin off
home_window = HomeWindow()
@@ -368,4 +321,4 @@ home_window.clearProperty("userid")
home_window.clearProperty("AccessToken")
home_window.clearProperty("Params")
log.info("Service shutting down")
log.debug("Service shutting down")