summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShaun <shaun@bluebit.com.au>2017-10-23 09:25:07 +1100
committerlearningit <scottyroscoe13@gmail.com>2017-10-22 18:25:07 -0400
commit9bf017ab4ba271f9bd533e10b0660ef493a6d74c (patch)
tree15628ca5edd506be69a5ec267ecbcee521e3ef77
parent1d357f7246cf4afa1b762553ad17ff3ee5c29197 (diff)
[plugin.video.embycon] 1.3.40 (#1450)
* plugin.video.embycon-1.3.40 * [plugin.video.embycon] 1.3.40 * [plugin.video.embycon] 1.3.40 * [plugin.video.embycon] 1.3.40
-rw-r--r--plugin.video.embycon/addon.xml2
-rw-r--r--plugin.video.embycon/resources/language/resource.language.en_gb/strings.po28
-rw-r--r--plugin.video.embycon/resources/lib/action_menu.py46
-rw-r--r--plugin.video.embycon/resources/lib/downloadutils.py30
-rw-r--r--plugin.video.embycon/resources/lib/functions.py369
-rw-r--r--plugin.video.embycon/resources/lib/menu_functions.py33
-rw-r--r--plugin.video.embycon/resources/lib/play_utils.py27
-rw-r--r--plugin.video.embycon/resources/lib/translation.py6
-rw-r--r--plugin.video.embycon/resources/lib/utils.py45
-rw-r--r--plugin.video.embycon/resources/lib/widgets.py398
-rw-r--r--plugin.video.embycon/resources/settings.xml10
-rw-r--r--plugin.video.embycon/resources/skins/default/720p/ActionMenu.xml67
-rw-r--r--plugin.video.embycon/resources/skins/default/720p/ResumeDialog.xml1
-rw-r--r--plugin.video.embycon/resources/skins/skin.estuary/xml/Home-17.1.xml12
-rw-r--r--plugin.video.embycon/resources/skins/skin.estuary/xml/Home-17.3-elec.xml1064
-rw-r--r--plugin.video.embycon/resources/skins/skin.estuary/xml/Home-17.3.xml18
-rw-r--r--plugin.video.embycon/service.py57
17 files changed, 1938 insertions, 275 deletions
diff --git a/plugin.video.embycon/addon.xml b/plugin.video.embycon/addon.xml
index fc03295..e985c77 100644
--- a/plugin.video.embycon/addon.xml
+++ b/plugin.video.embycon/addon.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="plugin.video.embycon"
name="EmbyCon"
- version="1.3.24"
+ version="1.3.40"
provider-name="Team B">
<requires>
<import addon="xbmc.python" version="2.24.0"/>
diff --git a/plugin.video.embycon/resources/language/resource.language.en_gb/strings.po b/plugin.video.embycon/resources/language/resource.language.en_gb/strings.po
index 3394583..17e02ed 100644
--- a/plugin.video.embycon/resources/language/resource.language.en_gb/strings.po
+++ b/plugin.video.embycon/resources/language/resource.language.en_gb/strings.po
@@ -94,6 +94,14 @@ msgctxt "#30025"
msgid "Password:"
msgstr ""
+msgctxt "#30026"
+msgid "Widget item select action"
+msgstr ""
+
+msgctxt "#30027"
+msgid "Show watched in recently added"
+msgstr ""
+
msgctxt "#30044"
msgid "Incorrect Username/Password"
msgstr ""
@@ -187,7 +195,7 @@ msgid "Play Error"
msgstr ""
msgctxt "#30129"
-msgid "This item is not playable"
+msgid "Default"
msgstr ""
msgctxt "#30135"
@@ -327,7 +335,11 @@ msgid "Prompt to delete episode after %"
msgstr ""
msgctxt "#30218"
-msgid "Prompt to play next episode after %"
+msgid "Play next episode after %"
+msgstr ""
+
+msgctxt "#30219"
+msgid " - Prompt before play"
msgstr ""
msgctxt "#30220"
@@ -367,7 +379,7 @@ msgid "Episodes"
msgstr ""
msgctxt "#30236"
-msgid "Save"
+msgid "Action for h265(hevc) video files"
msgstr ""
msgctxt "#30237"
@@ -375,7 +387,7 @@ msgid "Start from beginning"
msgstr ""
msgctxt "#30238"
-msgid "Default Sort"
+msgid "Playback Overrides"
msgstr ""
msgctxt "#30245"
@@ -549,3 +561,11 @@ msgstr ""
msgctxt "#30288"
msgid " - Latest"
msgstr ""
+
+msgctxt "#30289"
+msgid "TV Show (Genre)"
+msgstr ""
+
+msgctxt "#30290"
+msgid "All"
+msgstr ""
diff --git a/plugin.video.embycon/resources/lib/action_menu.py b/plugin.video.embycon/resources/lib/action_menu.py
new file mode 100644
index 0000000..3521e44
--- /dev/null
+++ b/plugin.video.embycon/resources/lib/action_menu.py
@@ -0,0 +1,46 @@
+import xbmc
+import xbmcaddon
+import xbmcgui
+
+from simple_logging import SimpleLogging
+
+log = SimpleLogging(__name__)
+
+class ActionMenu(xbmcgui.WindowXMLDialog):
+
+ selected_action = None
+ action_items = None
+
+ def __init__(self, *args, **kwargs):
+ log.debug("ActionMenu: __init__")
+ xbmcgui.WindowXML.__init__(self, *args, **kwargs)
+
+ def onInit(self):
+ log.debug("ActionMenu: onInit")
+ self.action_exitkeys_id = [10, 13]
+
+ self.listControl = self.getControl(3000)
+ self.listControl.addItems(self.action_items)
+ self.setFocus(self.listControl)
+
+ bg_image = self.getControl(3010)
+ bg_image.setHeight(50 * len(self.action_items) + 20)
+
+ def onFocus(self, controlId):
+ pass
+
+ def doAction(self, actionID):
+ pass
+
+ def onClick(self, controlID):
+ if (controlID == 3000):
+ self.selected_action = self.listControl.getSelectedItem()
+ log.debug("ActionMenu: Selected Item:" + str(self.selected_action))
+ self.close()
+
+ def setActionItems(self, action_items):
+ self.action_items = action_items
+
+ def getActionItem(self):
+ return self.selected_action
+
diff --git a/plugin.video.embycon/resources/lib/downloadutils.py b/plugin.video.embycon/resources/lib/downloadutils.py
index de42284..3805038 100644
--- a/plugin.video.embycon/resources/lib/downloadutils.py
+++ b/plugin.video.embycon/resources/lib/downloadutils.py
@@ -81,12 +81,8 @@ class DownloadUtils():
def getArtwork(self, data, art_type, parent=False, index="0", width=10000, height=10000, server=None):
id = data.get("Id")
- '''
- if data.get("Type") == "Season": # For seasons: primary (poster), thumb and banner get season art, rest series art
- if art_type != "Primary" and art_type != "Thumb" and art_type != "Banner":
- id = data.get("SeriesId")
- '''
- if data.get("Type") == "Episode": # For episodes: primary (episode thumb) gets episode art, rest series art.
+
+ if data.get("Type") in ["Episode", "Season"]:
if art_type != "Primary" or parent == True:
id = data.get("SeriesId")
@@ -117,7 +113,7 @@ class DownloadUtils():
imageTag = data.get("ImageTags").get(art_type)
log.debug("Image Tag:" + imageTag)
elif (parent == True):
- if (itemType == "Episode") and (art_type == 'Primary'):
+ if (itemType == "Episode" or itemType == "Season") and art_type == 'Primary':
tagName = 'SeriesPrimaryImageTag'
idName = 'SeriesId'
else:
@@ -311,7 +307,7 @@ class DownloadUtils():
log.debug("EmbyCon Authentication Header : " + str(headers))
return headers
- def downloadUrl(self, url, suppress=False, postBody=None, method="GET", popup=0, authenticate=True):
+ def downloadUrl(self, url, suppress=False, postBody=None, method="GET", popup=0, authenticate=True, headers=None):
log.debug("downloadUrl")
settings = xbmcaddon.Addon(id='plugin.video.embycon')
@@ -325,6 +321,22 @@ class DownloadUtils():
if url.find("{ItemLimit}") != -1:
show_x_filtered_items = settings.getSetting("show_x_filtered_items")
url = url.replace("{ItemLimit}", show_x_filtered_items)
+ if url.find("{IsUnplayed}") != -1 or url.find("{,IsUnplayed}") != -1 or url.find("{IsUnplayed,}") != -1 \
+ or url.find("{,IsUnplayed,}") != -1:
+ show_latest_unplayed = settings.getSetting("show_latest_unplayed") == "true"
+ if show_latest_unplayed:
+ url = url.replace("{IsUnplayed}", "")
+ url = url.replace("{,IsUnplayed}", "")
+ url = url.replace("{IsUnplayed,}", "")
+ url = url.replace("{,IsUnplayed,}", "")
+ elif url.find("{IsUnplayed}") != -1:
+ url = url.replace("{IsUnplayed}", "IsUnplayed")
+ elif url.find("{,IsUnplayed}") != -1:
+ url = url.replace("{,IsUnplayed}", ",IsUnplayed")
+ elif url.find("{IsUnplayed,}") != -1:
+ url = url.replace("{IsUnplayed,}", "IsUnplayed,")
+ elif url.find("{,IsUnplayed,}") != -1:
+ url = url.replace("{,IsUnplayed,}", ",IsUnplayed,")
log.debug(url)
return_data = "null"
@@ -395,6 +407,8 @@ class DownloadUtils():
return_data = gzipper.read()
else:
return_data = retData
+ if headers is not None and isinstance(headers, dict):
+ headers.update(data.getheaders())
log.debug("Data Len After : " + str(len(return_data)))
log.debug("====== 200 returned =======")
log.debug("Content-Type : " + str(contentType))
diff --git a/plugin.video.embycon/resources/lib/functions.py b/plugin.video.embycon/resources/lib/functions.py
index 34f0322..6f8f44e 100644
--- a/plugin.video.embycon/resources/lib/functions.py
+++ b/plugin.video.embycon/resources/lib/functions.py
@@ -25,6 +25,8 @@ from simple_logging import SimpleLogging
from menu_functions import displaySections, showMovieAlphaList, showGenreList, showWidgets, showSearch
from translation import i18n
from server_sessions import showServerSessions
+from action_menu import ActionMenu
+from widgets import getWidgetContent, getWidgetContentCast, getWidgetContentSimilar, getWidgetContentNextUp, getSuggestions, getWidgetUrlContent, checkForNewContent
__addon__ = xbmcaddon.Addon(id='plugin.video.embycon')
__addondir__ = xbmc.translatePath(__addon__.getAddonInfo('profile'))
@@ -63,7 +65,6 @@ def mainEntryPoint():
except:
params = {}
- checkService()
home_window = HomeWindow()
if (len(params) == 0):
@@ -108,10 +109,14 @@ def mainEntryPoint():
delete(item_id)
elif mode == "MOVIE_ALPHA":
showMovieAlphaList()
- elif mode == "MOVIE_GENRA":
+ elif mode == "MOVIE_GENRE":
showGenreList()
+ elif mode == "SERIES_GENRE":
+ showGenreList(item_type="series")
elif mode == "WIDGETS":
showWidgets()
+ elif mode == "SHOW_MENU":
+ showMenu(params)
elif mode == "SHOW_SETTINGS":
__addon__.openSettings()
WINDOW = xbmcgui.getCurrentWindowId()
@@ -122,7 +127,17 @@ def mainEntryPoint():
home_window.setProperty("force_data_reload", "true")
xbmc.executebuiltin("Container.Refresh")
elif mode == "WIDGET_CONTENT":
- getWigetContent(int(sys.argv[1]), params)
+ getWidgetContent(int(sys.argv[1]), params)
+ elif mode == "WIDGET_CONTENT_CAST":
+ getWidgetContentCast(int(sys.argv[1]), params)
+ elif mode == "WIDGET_CONTENT_SIMILAR":
+ getWidgetContentSimilar(int(sys.argv[1]), params)
+ elif mode == "WIDGET_CONTENT_NEXTUP":
+ getWidgetContentNextUp(int(sys.argv[1]), params)
+ elif mode == "WIDGET_CONTENT_SUGGESTIONS":
+ getSuggestions(int(sys.argv[1]), params)
+ elif mode == "WIDGET_CONTENT_URL":
+ getWidgetUrlContent(int(sys.argv[1]), params)
elif mode == "PARENT_CONTENT":
checkServer(notify=False)
showParentContent(sys.argv[0], int(sys.argv[1]), params)
@@ -187,6 +202,7 @@ def markWatched(item_id):
downloadUtils.downloadUrl(url, postBody="", method="POST")
home_window = HomeWindow()
home_window.setProperty("force_data_reload", "true")
+ checkForNewContent()
xbmc.executebuiltin("Container.Refresh")
@@ -196,6 +212,7 @@ def markUnwatched(item_id):
downloadUtils.downloadUrl(url, method="DELETE")
home_window = HomeWindow()
home_window.setProperty("force_data_reload", "true")
+ checkForNewContent()
xbmc.executebuiltin("Container.Refresh")
@@ -205,6 +222,7 @@ def markFavorite(item_id):
downloadUtils.downloadUrl(url, postBody="", method="POST")
home_window = HomeWindow()
home_window.setProperty("force_data_reload", "true")
+ checkForNewContent()
xbmc.executebuiltin("Container.Refresh")
@@ -214,6 +232,7 @@ def unmarkFavorite(item_id):
downloadUtils.downloadUrl(url, method="DELETE")
home_window = HomeWindow()
home_window.setProperty("force_data_reload", "true")
+ checkForNewContent()
xbmc.executebuiltin("Container.Refresh")
@@ -226,6 +245,8 @@ def delete(item_id):
progress.create(i18n('deleting'), i18n('waiting_server_delete'))
downloadUtils.downloadUrl(url, method="DELETE")
progress.close()
+ home_window = HomeWindow()
+ checkForNewContent()
xbmc.executebuiltin("Container.Refresh")
@@ -248,6 +269,8 @@ def addGUIItem(url, details, extraData, display_options, folder=True):
# Create the URL to pass to the item
if folder:
u = sys.argv[0] + "?url=" + urllib.quote(url) + mode + "&media_type=" + extraData["itemtype"]
+ if extraData.get("name_format"):
+ u += '&name_format=' + urllib.quote(extraData.get("name_format"))
else:
u = sys.argv[0] + "?item_id=" + url + "&mode=PLAY"
@@ -257,7 +280,7 @@ def addGUIItem(url, details, extraData, display_options, folder=True):
listItemName = details.get('title', i18n('unknown'))
# calculate percentage
- cappedPercentage = None
+ cappedPercentage = 0
if (extraData.get('resumetime') != None and int(extraData.get('resumetime')) > 0):
duration = float(extraData.get('duration'))
if (duration > 0):
@@ -270,10 +293,6 @@ def addGUIItem(url, details, extraData, display_options, folder=True):
watched = int(extraData.get('WatchedEpisodes'))
percentage = int((float(watched) / float(totalItems)) * 100.0)
cappedPercentage = percentage
- if (cappedPercentage == 0):
- cappedPercentage = None
- if (cappedPercentage == 100):
- cappedPercentage = None
countsAdded = False
addCounts = display_options.get("addCounts", True)
@@ -282,7 +301,10 @@ def addGUIItem(url, details, extraData, display_options, folder=True):
listItemName = listItemName + " (" + extraData.get('UnWatchedEpisodes') + ")"
addResumePercent = display_options.get("addResumePercent", True)
- if (countsAdded == False and addResumePercent and details.get('title') != None and cappedPercentage != None):
+ if (countsAdded == False
+ and addResumePercent
+ and details.get('title') != None
+ and cappedPercentage not in [0, 100]):
listItemName = listItemName + " (" + str(cappedPercentage) + "%)"
subtitle_available = display_options.get("addSubtitleAvailable", False)
@@ -300,7 +322,7 @@ def addGUIItem(url, details, extraData, display_options, folder=True):
log.debug("Setting thumbnail as " + thumbPath)
# calculate percentage
- if (cappedPercentage != None):
+ if (cappedPercentage != 0):
list_item.setProperty("complete_percentage", str(cappedPercentage))
# For all end items
@@ -312,7 +334,8 @@ def addGUIItem(url, details, extraData, display_options, folder=True):
# StartPercent
- artTypes = ['thumb', 'poster', 'fanart', 'clearlogo', 'discart', 'banner', 'clearart', 'landscape', 'tvshow.poster']
+ artTypes = ['thumb', 'poster', 'fanart', 'clearlogo', 'discart', 'banner', 'clearart',
+ 'landscape', 'tvshow.poster', 'tvshow.clearart', 'tvshow.banner', 'tvshow.landscape']
artLinks = {}
for artType in artTypes:
artLinks[artType] = extraData.get(artType, '')
@@ -352,6 +375,8 @@ def addGUIItem(url, details, extraData, display_options, folder=True):
videoInfoLabels["director"] = extraData.get('director')
videoInfoLabels["writer"] = extraData.get('writer')
videoInfoLabels["year"] = extraData.get('year')
+ videoInfoLabels["premiered"] = extraData.get('premieredate')
+ videoInfoLabels["dateadded"] = extraData.get('dateadded')
videoInfoLabels["studio"] = extraData.get('studio')
videoInfoLabels["genre"] = extraData.get('genre')
@@ -477,6 +502,7 @@ def setSort(pluginhandle, viewType):
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_DATEADDED)
xbmcplugin.addSortMethod(pluginhandle, xbmcplugin.SORT_METHOD_GENRE)
xbmcplugin.addSortMethod(pluginhandle, xbmcplugin.SORT_METHOD_UNSORTED)
xbmcplugin.addSortMethod(pluginhandle, xbmcplugin.SORT_METHOD_NONE)
@@ -539,6 +565,15 @@ def getContent(url, params):
xbmcplugin.endOfDirectory(pluginhandle, cacheToDisc=False)
+ # if the view master addon is available then run the script
+ try:
+ view_addon = xbmcaddon.Addon("script.viewmaster")
+ if view_addon is not None:
+ xbmc.executebuiltin('RunScript(' + xbmc.translatePath(
+ "special://home/addons/script.viewmaster/default.py") + ',' + viewType + ')')
+ except:
+ pass
+
if (progress != None):
progress.update(100, i18n('done'))
progress.close()
@@ -596,7 +631,10 @@ def processDirectory(results, progress, params):
item_count = len(result)
current_item = 1
-
+ first_season_item = None
+ total_unwatched = 0
+ total_episodes = 0
+ total_watched = 0
for item in result:
if (progress != None):
@@ -609,16 +647,27 @@ def processDirectory(results, progress, params):
item_type = str(item.get("Type")).encode('utf-8')
- tempEpisode = item.get("IndexNumber")
- if tempEpisode is not None:
- if tempEpisode < 10:
- tempEpisode = "0" + str(tempEpisode)
+ if item_type == "Season" and first_season_item is None:
+ first_season_item = item
+
+ # set the episode number
+ tempEpisode = ""
+ if item_type == "Episode":
+ tempEpisode = item.get("IndexNumber")
+ if tempEpisode is not None:
+ if tempEpisode < 10:
+ tempEpisode = "0" + str(tempEpisode)
+ else:
+ tempEpisode = str(tempEpisode)
else:
- tempEpisode = str(tempEpisode)
- else:
- tempEpisode = ""
+ tempEpisode = ""
- tempSeason = item.get("ParentIndexNumber")
+ # set the season number
+ tempSeason = None
+ if item_type == "Episode":
+ tempSeason = item.get("ParentIndexNumber")
+ elif item_type == "Season":
+ tempSeason = item.get("IndexNumber")
if tempSeason is not None:
if tempSeason < 10:
tempSeason = "0" + str(tempSeason)
@@ -664,6 +713,12 @@ def processDirectory(results, progress, params):
tokens = (item.get("PremiereDate")).split("T")
premiere_date = tokens[0]
+ try:
+ date_added = item['DateCreated']
+ date_added = date_added.split('.')[0].replace('T', " ")
+ except KeyError:
+ date_added = ""
+
# add the premiered date for Upcoming TV
if item.get("LocationType") == "Virtual":
airtime = item.get("AirTime")
@@ -797,6 +852,9 @@ def processDirectory(results, progress, params):
WatchedEpisodes = 0 if userData.get("UnplayedItemCount") == None else TotalEpisodes - userData.get("UnplayedItemCount")
UnWatchedEpisodes = 0 if userData.get("UnplayedItemCount") == None else userData.get("UnplayedItemCount")
NumEpisodes = TotalEpisodes
+ total_unwatched += UnWatchedEpisodes
+ total_episodes += TotalEpisodes
+ total_watched += WatchedEpisodes
art = getArt(item, server)
# Populate the extraData list
@@ -809,12 +867,16 @@ def processDirectory(results, progress, params):
'clearart': art['clearart'],
'landscape': art['landscape'],
'tvshow.poster': art['tvshow.poster'],
+ 'tvshow.clearart': art['tvshow.clearart'],
+ 'tvshow.banner': art['tvshow.banner'],
+ 'tvshow.landscape': art['tvshow.landscape'],
'id': id,
'mpaa': item.get("OfficialRating"),
'rating': item.get("CommunityRating"),
'criticrating': item.get("CriticRating"),
'year': production_year,
'premieredate': premiere_date,
+ 'dateadded': date_added,
'locationtype': item.get("LocationType"),
'studio': studio,
'genre': genre,
@@ -839,6 +901,7 @@ def processDirectory(results, progress, params):
'WatchedEpisodes': str(WatchedEpisodes),
'UnWatchedEpisodes': str(UnWatchedEpisodes),
'NumEpisodes': str(NumEpisodes),
+ 'OriginalTitle': item.get("Name").encode('utf-8'),
'itemtype': item_type,
'SubtitleLang': subtitle_lang,
'SubtitleAvailable': subtitle_available}
@@ -869,165 +932,95 @@ def processDirectory(results, progress, params):
u = id
dirItems.append(addGUIItem(u, details, extraData, display_options, folder=False))
- return dirItems
-
-def getWigetContent(handle, params):
- log.debug("getWigetContent Called" + str(params))
- server = downloadUtils.getServer()
-
- type = params.get("type")
- if (type == None):
- log.error("getWigetContent type not set")
- return
-
- itemsUrl = ("{server}/emby/Users/{userid}/Items"
- "?Limit=20"
- "&format=json"
- "&ImageTypeLimit=1"
- "&IsMissing=False")
-
- if (type == "recent_movies"):
- xbmcplugin.setContent(handle, 'movies')
- itemsUrl += ("&Recursive=true"
- "&SortBy=DateCreated"
- "&SortOrder=Descending"
- "&Filters=IsUnplayed,IsNotFolder"
- "&IsVirtualUnaired=false"
- "&IsMissing=False"
- "&IncludeItemTypes=Movie")
- elif (type == "inprogress_movies"):
- xbmcplugin.setContent(handle, 'movies')
- itemsUrl += ("&Recursive=true"
- "&SortBy=DatePlayed"
- "&SortOrder=Descending"
- "&Filters=IsResumable"
- "&IsVirtualUnaired=false"
- "&IsMissing=False"
- "&IncludeItemTypes=Movie")
- elif (type == "random_movies"):
- xbmcplugin.setContent(handle, 'movies')
- itemsUrl += ("&Recursive=true"
- "&SortBy=Random"
- "&SortOrder=Descending"
- "&Filters=IsUnplayed,IsNotFolder"
- "&IsVirtualUnaired=false"
- "&IsMissing=False"
- "&IncludeItemTypes=Movie")
- elif (type == "recent_episodes"):
- xbmcplugin.setContent(handle, 'episodes')
- itemsUrl += ("&Recursive=true"
- "&SortBy=DateCreated"
- "&SortOrder=Descending"
- "&Filters=IsUnplayed,IsNotFolder"
- "&IsVirtualUnaired=false"
- "&IsMissing=False"
- "&IncludeItemTypes=Episode")
- elif (type == "inprogress_episodes"):
- xbmcplugin.setContent(handle, 'episodes')
- itemsUrl += ("&Recursive=true"
- "&SortBy=DatePlayed"
- "&SortOrder=Descending"
- "&Filters=IsResumable"
- "&IsVirtualUnaired=false"
- "&IsMissing=False"
- "&IncludeItemTypes=Episode")
- elif (type == "nextup_episodes"):
- xbmcplugin.setContent(handle, 'episodes')
- itemsUrl = ("{server}/emby/Shows/NextUp"
- "?Limit=20"
- "&userid={userid}"
- "&Recursive=true"
- "&format=json"
- "&ImageTypeLimit=1")
-
- log.debug("WIDGET_DATE_URL: " + itemsUrl)
-
- # get the items
- jsonData = downloadUtils.downloadUrl(itemsUrl, suppress=False, popup=1)
- log.debug("Recent(Items) jsonData: " + jsonData)
- result = json.loads(jsonData)
-
- if result is None:
- return []
-
- result = result.get("Items")
- if (result == None):
- result = []
-
- itemCount = 1
- listItems = []
- for item in result:
- item_id = item.get("Id")
- name = item.get("Name")
- episodeDetails = ""
- log.debug("WIDGET_DATE_NAME: " + name)
-
- title = item.get("Name")
- tvshowtitle = ""
-
- if (item.get("Type") == "Episode" and item.get("SeriesName") != None):
-
- eppNumber = "X"
- tempEpisodeNumber = "0"
- if (item.get("IndexNumber") != None):
- eppNumber = item.get("IndexNumber")
- if eppNumber < 10:
- tempEpisodeNumber = "0" + str(eppNumber)
- else:
- tempEpisodeNumber = str(eppNumber)
-
- seasonNumber = item.get("ParentIndexNumber")
- if seasonNumber < 10:
- tempSeasonNumber = "0" + str(seasonNumber)
- else:
- tempSeasonNumber = str(seasonNumber)
-
- episodeDetails = "S" + tempSeasonNumber + "E" + tempEpisodeNumber
- name = item.get("SeriesName") + " " + episodeDetails
- tvshowtitle = episodeDetails
- title = item.get("SeriesName")
-
- art = getArt(item, server, widget=True)
-
- if kodi_version > 17:
- list_item = xbmcgui.ListItem(label=name, iconImage=art['thumb'], offscreen=True)
- else:
- list_item = xbmcgui.ListItem(label=name, iconImage=art['thumb'])
-
- # list_item.setLabel2(episodeDetails)
- list_item.setInfo(type="Video", infoLabels={"title": title, "tvshowtitle": tvshowtitle})
- list_item.setProperty('fanart_image', art['fanart']) # back compat
- list_item.setProperty('discart', art['discart']) # not avail to setArt
- list_item.setArt(art)
- # add count
- list_item.setProperty("item_index", str(itemCount))
- itemCount = itemCount + 1
-
- list_item.setProperty('IsPlayable', 'true')
-
- totalTime = str(int(float(item.get("RunTimeTicks", "0")) / (10000000 * 60)))
- list_item.setProperty('TotalTime', str(totalTime))
-
- # add progress percent
- userData = item.get("UserData")
- if (userData != None):
- playBackTicks = float(userData.get("PlaybackPositionTicks"))
- if (playBackTicks != None and playBackTicks > 0):
- runTimeTicks = float(item.get("RunTimeTicks", "0"))
- if (runTimeTicks > 0):
- playBackPos = int(((playBackTicks / 1000) / 10000) / 60)
- list_item.setProperty('ResumeTime', str(playBackPos))
-
- percentage = int((playBackTicks / runTimeTicks) * 100.0)
- list_item.setProperty("complete_percentage", str(percentage))
-
- playurl = "plugin://plugin.video.embycon/?item_id=" + item_id + '&mode=PLAY'
+ # add the all episodes item
+ if first_season_item is not None:
+ series_url = ('{server}/emby/Users/{userid}/items' +
+ '?ParentId=' + str(first_season_item.get("SeriesId")).encode('utf-8') +
+ '&IsVirtualUnAired=false' +
+ '&IsMissing=false' +
+ '&Fields=' + detailsString +
+ '&Recursive=true' +
+ '&IncludeItemTypes=Episode' +
+ '&format=json')
+ played = 0
+ overlay = "7"
+ if total_unwatched == 0:
+ played = 1
+ overlay = "6"
+ details = {'title': i18n('all'),
+ 'Overlay': overlay,
+ 'playcount': str(played)
+ }
+ art = getArt(first_season_item, server)
+ # Populate the extraData list
+ extraData = {'thumb': art['tvshow.poster'],
+ 'fanart': art['fanart'],
+ 'poster': art['tvshow.poster'],
+ 'banner': art['tvshow.banner'],
+ 'clearlogo': art['clearlogo'],
+ 'discart': art['discart'],
+ 'clearart': art['clearart'],
+ 'landscape': art['landscape'],
+ 'tvshow.poster': art['tvshow.poster'],
+ 'tvshow.clearart': art['tvshow.clearart'],
+ 'tvshow.banner': art['tvshow.banner'],
+ 'tvshow.landscape': art['tvshow.landscape'],
+ 'itemtype': 'Episodes',
+ 'UnWatchedEpisodes': str(total_unwatched),
+ 'TotalEpisodes': str(total_episodes),
+ 'WatchedEpisodes': str(total_watched),
+ 'playcount': str(played),
+ 'mode': 'GET_CONTENT',
+ 'name_format': 'Episode|episode_name_format'}
+ dirItems.append(addGUIItem(series_url, details, extraData, {}, folder=True))
- itemTupple = (playurl, list_item, False)
- listItems.append(itemTupple)
+ return dirItems
- xbmcplugin.addDirectoryItems(handle, listItems)
- xbmcplugin.endOfDirectory(handle, cacheToDisc=False)
+def showMenu(params):
+ log.debug("showMenu(): " + str(params))
+
+ action_items = []
+ li = xbmcgui.ListItem("Play")
+ li.setProperty('menu_id', 'play')
+ action_items.append(li)
+ li = xbmcgui.ListItem("Force Transcode")
+ li.setProperty('menu_id', 'transcode')
+ action_items.append(li)
+ li = xbmcgui.ListItem("Mark Watched")
+ li.setProperty('menu_id', 'mark_watched')
+ action_items.append(li)
+ li = xbmcgui.ListItem("Mark Unwatched")
+ li.setProperty('menu_id', 'mark_unwatched')
+ action_items.append(li)
+ li = xbmcgui.ListItem("Delete")
+ li.setProperty('menu_id', 'delete')
+ action_items.append(li)
+
+ action_menu = ActionMenu("ActionMenu.xml", PLUGINPATH, "default", "720p")
+ action_menu.setActionItems(action_items)
+ action_menu.doModal()
+ selected_action_item = action_menu.getActionItem()
+ selected_action = ""
+ if selected_action_item is not None:
+ selected_action = selected_action_item.getProperty('menu_id')
+ log.debug("Menu Action Selected: " + str(selected_action_item))
+ del action_menu
+
+ if selected_action == "play":
+ log.debug("Play Item")
+ PLAY(params)
+ elif selected_action == "transcode":
+ params['force_transcode'] = 'true'
+ PLAY(params)
+ elif selected_action == "mark_watched":
+ markWatched(params["item_id"])
+ xbmc.executebuiltin("XBMC.ReloadSkin()")
+ elif selected_action == "mark_unwatched":
+ markUnwatched(params["item_id"])
+ xbmc.executebuiltin("XBMC.ReloadSkin()")
+ elif selected_action == "delete":
+ delete(params["item_id"])
+ xbmc.executebuiltin("XBMC.ReloadSkin()")
def showContent(pluginName, handle, params):
@@ -1067,28 +1060,6 @@ def showParentContent(pluginName, handle, params):
log.debug("showParentContent Content Url : " + str(contentUrl))
getContent(contentUrl, params)
-def checkService():
- home_window = HomeWindow()
- time_stamp = home_window.getProperty("Service_Timestamp")
- loops = 0
- while not time_stamp and not xbmc.Monitor().abortRequested():
- loops = loops + 1
- if loops == 100:
- log.error("EmbyCon Service Not Running, no time stamp, exiting")
- xbmcgui.Dialog().ok(i18n('error'), i18n('service_not_running'), i18n('restart_kodi'))
- sys.exit()
- xbmc.sleep(200)
- time_stamp = home_window.getProperty("Service_Timestamp")
-
- log.debug("EmbyCon Service Timestamp: " + time_stamp)
- log.debug("EmbyCon Current Timestamp: " + str(int(time.time())))
-
- if ((int(time_stamp) + 240) < int(time.time())):
- log.error("EmbyCon Service Not Running, time stamp to old, exiting")
- xbmcgui.Dialog().ok(i18n('error'), i18n('service_not_running'), i18n('restart_kodi'))
- sys.exit()
-
-
def search(handle, params):
log.debug('search Called: ' + str(params))
item_type = params.get('item_type')
diff --git a/plugin.video.embycon/resources/lib/menu_functions.py b/plugin.video.embycon/resources/lib/menu_functions.py
index 6fc0838..8d21d4f 100644
--- a/plugin.video.embycon/resources/lib/menu_functions.py
+++ b/plugin.video.embycon/resources/lib/menu_functions.py
@@ -20,7 +20,7 @@ downloadUtils = DownloadUtils()
__addon__ = xbmcaddon.Addon(id='plugin.video.embycon')
-def showGenreList():
+def showGenreList(item_type=None):
log.debug("== ENTER: showGenreList() ==")
server = downloadUtils.getServer()
@@ -29,8 +29,20 @@ def showGenreList():
detailsString = getDetailsString()
+ kodi_type = "Movies"
+ emby_type = "Movie"
+ if item_type is not None and item_type == "series":
+ emby_type = "Series"
+ kodi_type = "tvshows"
+
try:
- jsonData = downloadUtils.downloadUrl("{server}/emby/Genres?SortBy=SortName&SortOrder=Ascending&IncludeTypes=Movie&Recursive=true&UserId={userid}&format=json")
+ jsonData = downloadUtils.downloadUrl("{server}/emby/Genres?" +
+ "SortBy=SortName" +
+ "&SortOrder=Ascending" +
+ "&IncludeItemTypes=" + emby_type +
+ "&Recursive=true" +
+ "&UserId={userid}" +
+ "&format=json")
log.debug("GENRE_LIST_DATA : " + jsonData)
except Exception, msg:
error = "Get connect : " + str(msg)
@@ -44,11 +56,11 @@ def showGenreList():
for genre in result:
item_data = {}
item_data['title'] = genre.get("Name")
- item_data['media_type'] = "Movies"
+ item_data['media_type'] = kodi_type
item_data['thumbnail'] = downloadUtils.getArtwork(genre, "Thumb", server=server)
item_data['path'] = ('{server}/emby/Users/{userid}/Items?Fields=' + detailsString +
'&Recursive=true&GenreIds=' + genre.get("Id") +
- '&IncludeItemTypes=Movie' +
+ '&IncludeItemTypes=' + emby_type +
'&ImageTypeLimit=1&format=json')
collections.append(item_data)
@@ -129,8 +141,9 @@ def displaySections():
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")
+ addMenuDirectoryItem(i18n('movies_genre'), "plugin://plugin.video.embycon/?mode=MOVIE_GENRE")
addMenuDirectoryItem(i18n('movies_az'), "plugin://plugin.video.embycon/?mode=MOVIE_ALPHA")
+ addMenuDirectoryItem(i18n('tvshow_genre'), "plugin://plugin.video.embycon/?mode=SERIES_GENRE")
addMenuDirectoryItem(i18n('search'), "plugin://plugin.video.embycon/?mode=SEARCH")
addMenuDirectoryItem(i18n('show_clients'), "plugin://plugin.video.embycon/?mode=SHOW_SERVER_SESSIONS")
@@ -265,7 +278,7 @@ def getCollections(detailsString):
'&Fields=' + detailsString +
'&SortBy=DateCreated' +
'&SortOrder=Descending' +
- '&Filters=IsUnplayed,IsNotFolder' +
+ '&Filters={IsUnplayed,}IsNotFolder' +
'&Recursive=true' +
'&IncludeItemTypes=Episode' +
'&ImageTypeLimit=1' +
@@ -326,7 +339,7 @@ def getCollections(detailsString):
'&Fields=' + detailsString +
'&SortBy=DateCreated' +
'&SortOrder=Descending' +
- '&Filters=IsUnplayed,IsNotFolder' +
+ '&Filters={IsUnplayed,}IsNotFolder' +
'&ImageTypeLimit=1' +
'&format=json'),
'media_type': collection_type})
@@ -377,7 +390,7 @@ def getCollections(detailsString):
'&SortBy=DateCreated' +
'&Fields=' + detailsString +
'&SortOrder=Descending' +
- '&Filters=IsUnplayed,IsNotFolder' +
+ '&Filters={IsUnplayed,}IsNotFolder' +
'&IncludeItemTypes=Movie' +
'&ImageTypeLimit=1' +
'&format=json')
@@ -451,7 +464,7 @@ def getCollections(detailsString):
'&SortBy=DateCreated' +
'&Fields=' + detailsString +
'&SortOrder=Descending' +
- '&Filters=IsUnplayed' +
+ '&Filters={IsUnplayed}' +
'&IsVirtualUnaired=false' +
'&IsMissing=False' +
'&IncludeItemTypes=Episode' +
@@ -483,7 +496,7 @@ def getCollections(detailsString):
'&SortBy=DateCreated' +
'&Fields=' + detailsString +
'&SortOrder=Descending' +
- '&Filters=IsUnplayed,IsNotFolder' +
+ '&Filters={IsUnplayed,}IsNotFolder' +
'&IsVirtualUnaired=false' +
'&IsMissing=False' +
'&IncludeItemTypes=Episode' +
diff --git a/plugin.video.embycon/resources/lib/play_utils.py b/plugin.video.embycon/resources/lib/play_utils.py
index f7cba7c..8e579f1 100644
--- a/plugin.video.embycon/resources/lib/play_utils.py
+++ b/plugin.video.embycon/resources/lib/play_utils.py
@@ -30,7 +30,6 @@ def playFile(play_info):
settings = xbmcaddon.Addon('plugin.video.embycon')
addon_path = settings.getAddonInfo('path')
- playback_type = settings.getSetting("playback_type")
jump_back_amount = int(settings.getSetting("jump_back_amount"))
server = downloadUtils.getServer()
@@ -89,12 +88,12 @@ def playFile(play_info):
playurl, listitem_props = PlayUtils().getStrmDetails(result)
if not playurl:
- playurl = PlayUtils().getPlayUrl(id, result, force_transcode)
+ playurl, playback_type = PlayUtils().getPlayUrl(id, result, force_transcode)
log.debug("Play URL: " + playurl + " ListItem Properties: " + str(listitem_props))
playback_type_string = "DirectPlay"
- if playback_type == "2" or force_transcode:
+ if playback_type == "2":
playback_type_string = "Transcode"
elif playback_type == "1":
playback_type_string = "DirectStream"
@@ -108,9 +107,22 @@ def playFile(play_info):
else:
result["Overview"] = playback_type_string
- list_item = xbmcgui.ListItem(label=result.get("Name", i18n('missing_title')), path=playurl)
+ item_title = result.get("Name", i18n('missing_title'))
+ add_episode_number = settings.getSetting('addEpisodeNumber') == 'true'
+ if result.get("Type") == "Episode" and add_episode_number:
+ episode_num = result.get("IndexNumber")
+ if episode_num is not None:
+ if episode_num < 10:
+ episode_num = "0" + str(episode_num)
+ else:
+ episode_num = str(episode_num)
+ else:
+ episode_num = ""
+ item_title = episode_num + " - " + item_title
+
+ list_item = xbmcgui.ListItem(label=item_title, path=playurl)
- list_item = setListItemProps(id, list_item, result, server, listitem_props)
+ list_item = setListItemProps(id, list_item, result, server, listitem_props, item_title)
playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
playlist.clear()
@@ -138,7 +150,7 @@ def playFile(play_info):
xbmc.sleep(100)
# xbmc.Player().play()
-def setListItemProps(id, listItem, result, server, extra_props):
+def setListItemProps(id, listItem, result, server, extra_props, title):
# set up item and item info
thumbID = id
eppNum = -1
@@ -152,13 +164,14 @@ def setListItemProps(id, listItem, result, server, extra_props):
listItem.setProperty('IsPlayable', 'true')
listItem.setProperty('IsFolder', 'false')
+ listItem.setProperty('id', result.get("Id"))
for prop in extra_props:
listItem.setProperty(prop[0], prop[1])
# play info
details = {
- 'title': result.get("Name", i18n('missing_title')),
+ 'title': title,
'plot': result.get("Overview")
}
diff --git a/plugin.video.embycon/resources/lib/translation.py b/plugin.video.embycon/resources/lib/translation.py
index f0c2214..2f327c5 100644
--- a/plugin.video.embycon/resources/lib/translation.py
+++ b/plugin.video.embycon/resources/lib/translation.py
@@ -50,9 +50,7 @@ STRINGS = {
'series': 30233,
'seasons': 30234,
'episodes': 30235,
- 'save': 30236,
'start_from_beginning': 30237,
- 'default_sort': 30238,
'next_page': 30245,
'search': 30246,
'widgets': 30247,
@@ -97,5 +95,7 @@ STRINGS = {
'_unwatched': 30285,
'movies_unwatched': 30286,
'tvshows_latest' : 30287,
- '_latest' : 30288
+ '_latest' : 30288,
+ 'tvshow_genre': 30289,
+ 'all': 30290
}
diff --git a/plugin.video.embycon/resources/lib/utils.py b/plugin.video.embycon/resources/lib/utils.py
index 05a1094..9c6a8d3 100644
--- a/plugin.video.embycon/resources/lib/utils.py
+++ b/plugin.video.embycon/resources/lib/utils.py
@@ -24,14 +24,32 @@ class PlayUtils():
log.debug("playback_type: FORCED_TRANSCODE")
playurl = None
+ is_h265 = False
+ streams = result.get("MediaStreams", [])
+ for stream in streams:
+ if stream.get("Type", "") == "Video" and stream.get("Codec", "") in ["hevc", "h265"]:
+ is_h265 = True
+ break
+ if is_h265:
+ log.debug("H265_IS_TRUE")
+ h265_action = addonSettings.getSetting("h265_action")
+ if h265_action == "1":
+ log.debug("H265 override play action: setting to Direct Streaming")
+ playback_type = "1"
+ elif h265_action == "2":
+ log.debug("H265 override play action: setting to Transcode Streaming")
+ playback_type = "2"
+
+ if force_transcode:
+ playback_type = "2"
+
# transcode
- if playback_type == "2" or force_transcode:
+ if playback_type == "2":
playback_bitrate = addonSettings.getSetting("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"))]
+ playback_max_width = addonSettings.getSetting("playback_max_width")
playback_video_force_8 = addonSettings.getSetting("playback_video_force_8") == "true"
clientInfo = ClientInformation()
@@ -78,7 +96,7 @@ class PlayUtils():
playurl = playurl + "&api_key=" + user_token
log.debug("Playback URL: " + playurl)
- return playurl.encode('utf-8')
+ return playurl.encode('utf-8'), playback_type
def getStrmDetails(self, result):
playurl = None
@@ -112,7 +130,7 @@ def getDetailsString():
include_people = addonSettings.getSetting("include_people") == "true"
include_overview = addonSettings.getSetting("include_overview") == "true"
- detailsString = "EpisodeCount,SeasonCount,Path,Genres,Studios,CumulativeRunTimeTicks,Etag"
+ detailsString = "DateCreated,EpisodeCount,SeasonCount,Path,Genres,Studios,CumulativeRunTimeTicks,Etag"
if include_media:
detailsString += ",MediaStreams"
@@ -151,7 +169,10 @@ def getArt(item, server, widget=False):
'clearart': '',
'discart': '',
'landscape': '',
- 'tvshow.poster': ''
+ 'tvshow.poster': '',
+ 'tvshow.clearart': '',
+ 'tvshow.banner': '',
+ 'tvshow.landscape': ''
}
item_id = item.get("Id")
@@ -164,10 +185,20 @@ def getArt(item, server, widget=False):
else:
art['thumb'] = downloadUtils.getArtwork(item, "Primary", server=server)
+ if item.get("Type") == "Episode" or item.get("Type") == "Season":
+ art['tvshow.poster'] = downloadUtils.getArtwork(item, "Primary", parent=True, server=server)
+ art['tvshow.clearart'] = downloadUtils.getArtwork(item, "Logo", parent=True, server=server)
+ art['tvshow.banner'] = downloadUtils.getArtwork(item, "Banner", parent=True, server=server)
+ art['tvshow.landscape'] = downloadUtils.getArtwork(item, "Thumb", parent=True, server=server)
+ elif item.get("Type") == "Series":
+ art['tvshow.poster'] = downloadUtils.getArtwork(item, "Primary", parent=False, server=server)
+ art['tvshow.clearart'] = downloadUtils.getArtwork(item, "Logo", parent=False, server=server)
+ art['tvshow.banner'] = downloadUtils.getArtwork(item, "Banner", parent=False, server=server)
+ art['tvshow.landscape'] = downloadUtils.getArtwork(item, "Thumb", parent=False, server=server)
+
if item.get("Type") == "Episode":
art['thumb'] = art['thumb'] if art['thumb'] else downloadUtils.getArtwork(item, "Thumb", server=server)
art['landscape'] = art['thumb'] if art['thumb'] else downloadUtils.getArtwork(item, "Thumb", parent=True, server=server)
- art['tvshow.poster'] = downloadUtils.getArtwork(item, "Primary", parent=True, server=server)
else:
art['poster'] = art['thumb']
diff --git a/plugin.video.embycon/resources/lib/widgets.py b/plugin.video.embycon/resources/lib/widgets.py
new file mode 100644
index 0000000..c3098d4
--- /dev/null
+++ b/plugin.video.embycon/resources/lib/widgets.py
@@ -0,0 +1,398 @@
+
+import xbmcaddon
+import xbmcplugin
+import xbmcgui
+import xbmc
+import json
+import urllib
+import hashlib
+
+from downloadutils import DownloadUtils
+from utils import getArt
+from datamanager import DataManager
+from simple_logging import SimpleLogging
+from kodi_utils import HomeWindow
+
+log = SimpleLogging(__name__)
+downloadUtils = DownloadUtils()
+dataManager = DataManager()
+kodi_version = int(xbmc.getInfoLabel('System.BuildVersion')[:2])
+
+def checkForNewContent():
+ log.debug("checkForNewContent Called")
+
+ added_url = ('{server}/emby/Users/{userid}/Items' +
+ '?Recursive=true' +
+ '&limit=1' +
+ '&Fields=DateCreated,Etag' +
+ '&SortBy=DateCreated' +
+ '&SortOrder=Descending' +
+ '&IncludeItemTypes=Movie,Episode' +
+ '&ImageTypeLimit=0' +
+ '&format=json')
+
+ added_result = downloadUtils.downloadUrl(added_url, suppress=True)
+ result = json.loads(added_result)
+ log.debug("LATEST_ADDED_ITEM:" + str(result))
+
+ last_added_date = ""
+ if result is not None:
+ items = result.get("Items", [])
+ if len(items) > 0:
+ item = items[0]
+ last_added_date = item.get("Etag", "")
+ log.debug("last_added_date: " + last_added_date)
+
+ played_url = ('{server}/emby/Users/{userid}/Items' +
+ '?Recursive=true' +
+ '&limit=1' +
+ '&Fields=DateCreated,Etag' +
+ '&SortBy=DatePlayed' +
+ '&SortOrder=Descending' +
+ '&IncludeItemTypes=Movie,Episode' +
+ '&ImageTypeLimit=0' +
+ '&format=json')
+
+ played_result = downloadUtils.downloadUrl(played_url, suppress=True)
+ result = json.loads(played_result)
+ log.debug("LATEST_PLAYED_ITEM:" + str(result))
+
+ last_played_date = ""
+ if result is not None:
+ items = result.get("Items", [])
+ if len(items) > 0:
+ item = items[0]
+ last_played_date = item.get("Etag", "")
+ log.debug("last_played_date: " + last_played_date)
+
+ home_window = HomeWindow()
+ current_widget_hash = home_window.getProperty("embycon_widget_reload")
+ log.debug("Current Widget Hash: " + str(current_widget_hash))
+
+ m = hashlib.md5()
+ m.update(last_played_date + last_added_date)
+ new_widget_hash = m.hexdigest()
+ log.debug("New Widget Hash: " + str(new_widget_hash))
+
+ if current_widget_hash != new_widget_hash:
+ home_window.setProperty("embycon_widget_reload", new_widget_hash)
+ log.debug("Setting New Widget Hash: " + str(new_widget_hash))
+
+
+def getWidgetUrlContent(handle, params):
+ log.debug("getWidgetUrlContent Called" + str(params))
+
+ request = params["url"]
+ request = urllib.unquote(request)
+ request = "{server}/emby/" + request + "&ImageTypeLimit=1&format=json"
+ log.debug("getWidgetUrlContent URL:" + request)
+
+ select_action = params.get("action", None)
+
+ listItems = populateWidgetItems(request, override_select_action=select_action)
+
+ xbmcplugin.addDirectoryItems(handle, listItems)
+ xbmcplugin.endOfDirectory(handle, cacheToDisc=False)
+
+
+def getSuggestions(handle, params):
+ log.debug("getSuggestions Called" + str(params))
+
+ itemsUrl = ("{server}/emby/Movies/Recommendations" +
+ "?userId={userid}" +
+ "&categoryLimit=1" +
+ "&ItemLimit=8" +
+ "&format=json" +
+ "&ImageTypeLimit=1" +
+ "&IsMissing=False")
+
+ listItems = populateWidgetItems(itemsUrl)
+
+ xbmcplugin.addDirectoryItems(handle, listItems)
+ xbmcplugin.endOfDirectory(handle, cacheToDisc=False)
+
+def getWidgetContentNextUp(handle, params):
+ log.debug("getWidgetContentNextUp Called" + str(params))
+
+ itemsUrl = ("{server}/emby/Shows/NextUp?SeriesId=" + params["id"] +
+ "&userId={userid}" +
+ "&Limit={ItemLimit}" +
+ "&format=json" +
+ "&ImageTypeLimit=1" +
+ "&IsMissing=False")
+
+ listItems = populateWidgetItems(itemsUrl)
+
+ xbmcplugin.addDirectoryItems(handle, listItems)
+ xbmcplugin.endOfDirectory(handle, cacheToDisc=False)
+
+
+def getWidgetContentSimilar(handle, params):
+ log.debug("getWisgetContentSimilarMovies Called" + str(params))
+
+ itemsUrl = ("{server}/emby/Items/" + params["id"] + "/Similar"
+ "?userId={userid}" +
+ "&Limit={ItemLimit}" +
+ "&format=json" +
+ "&ImageTypeLimit=1" +
+ "&IsMissing=False" +
+ "&fields=PrimaryImageAspectRatio,UserData,CanDelete")
+
+ listItems = populateWidgetItems(itemsUrl)
+
+ xbmcplugin.addDirectoryItems(handle, listItems)
+ xbmcplugin.endOfDirectory(handle, cacheToDisc=False)
+
+
+def getWidgetContentCast(handle, params):
+ log.debug("getWigetContentCast Called" + str(params))
+ server = downloadUtils.getServer()
+
+ id = params["id"]
+ jsonData = downloadUtils.downloadUrl("{server}/emby/Users/{userid}/Items/" + id + "?format=json",
+ suppress=False, popup=1)
+ result = json.loads(jsonData)
+ log.debug("ItemInfo: " + str(result))
+
+ listItems = []
+ people = result.get("People")
+ if (people != None):
+ for person in people:
+ #if (person.get("Type") == "Director"):
+ # director = director + person.get("Name") + ' '
+ #if (person.get("Type") == "Writing"):
+ # writer = person.get("Name")
+ #if (person.get("Type") == "Writer"):
+ # writer = person.get("Name")
+ if (person.get("Type") == "Actor"):
+ person_name = person.get("Name")
+ person_role = person.get("Role")
+ person_id = person.get("Id")
+ person_tag = person.get("PrimaryImageTag")
+ person_thumbnail = downloadUtils.imageUrl(person_id, "Primary", 0, 400, 400, person_tag, server=server)
+
+ if kodi_version > 17:
+ list_item = xbmcgui.ListItem(label=person_name, iconImage=person_thumbnail, offscreen=True)
+ else:
+ list_item = xbmcgui.ListItem(label=person_name, iconImage=person_thumbnail)
+
+ artLinks = {}
+ artLinks["thumb"] = person_thumbnail
+ artLinks["poster"] = person_thumbnail
+ list_item.setArt(artLinks)
+
+ if person_role:
+ list_item.setLabel2(person_role)
+
+ itemTupple = ("", list_item, False)
+ listItems.append(itemTupple)
+
+ xbmcplugin.addDirectoryItems(handle, listItems)
+ xbmcplugin.endOfDirectory(handle, cacheToDisc=False)
+
+
+def populateWidgetItems(itemsUrl, override_select_action=None):
+
+ server = downloadUtils.getServer()
+ settings = xbmcaddon.Addon(id='plugin.video.embycon')
+ select_action = settings.getSetting("widget_select_action")
+
+ if override_select_action is not None:
+ select_action = str(override_select_action)
+
+ log.debug("WIDGET_DATE_URL: " + itemsUrl)
+
+ # get the items
+ jsonData = downloadUtils.downloadUrl(itemsUrl, suppress=False, popup=1)
+ log.debug("Widget(Items) jsonData: " + jsonData)
+ result = json.loads(jsonData)
+
+ if result is not None and isinstance(result, dict) and result.get("Items") is not None:
+ simmilarTo = result.get("BaselineItemName", None)
+ result = result.get("Items")
+ elif result is not None and isinstance(result, list) and len(result) > 0:
+ simmilarTo = result[0].get("BaselineItemName", None)
+ result = result[0].get("Items")
+ else:
+ result = []
+
+ itemCount = 1
+ listItems = []
+ for item in result:
+ item_id = item.get("Id")
+ name = item.get("Name")
+ episodeDetails = ""
+ log.debug("WIDGET_DATE_NAME: " + name)
+
+ title = item.get("Name")
+ tvshowtitle = ""
+
+ if (item.get("Type") == "Episode" and item.get("SeriesName") != None):
+
+ eppNumber = "X"
+ tempEpisodeNumber = "0"
+ if (item.get("IndexNumber") != None):
+ eppNumber = item.get("IndexNumber")
+ if eppNumber < 10:
+ tempEpisodeNumber = "0" + str(eppNumber)
+ else:
+ tempEpisodeNumber = str(eppNumber)
+
+ seasonNumber = item.get("ParentIndexNumber")
+ if seasonNumber < 10:
+ tempSeasonNumber = "0" + str(seasonNumber)
+ else:
+ tempSeasonNumber = str(seasonNumber)
+
+ episodeDetails = "S" + tempSeasonNumber + "E" + tempEpisodeNumber
+ name = item.get("SeriesName") + " " + episodeDetails
+ tvshowtitle = episodeDetails
+ title = item.get("SeriesName")
+
+ art = getArt(item, server, widget=True)
+
+ if kodi_version > 17:
+ list_item = xbmcgui.ListItem(label=name, iconImage=art['thumb'], offscreen=True)
+ else:
+ list_item = xbmcgui.ListItem(label=name, iconImage=art['thumb'])
+
+ # list_item.setLabel2(episodeDetails)
+
+ production_year = item.get("ProductionYear")
+ if not production_year and item.get("PremiereDate"):
+ production_year = int(item.get("PremiereDate")[:4])
+
+ overlay = "0"
+ playCount = "0"
+
+ # add progress percent
+ userData = item.get("UserData")
+ if (userData != None):
+ if userData.get("Played") == True:
+ playCount = "1"
+ overlay = "5"
+ else:
+ overlay = "6"
+
+ playBackTicks = float(userData.get("PlaybackPositionTicks"))
+ if (playBackTicks != None and playBackTicks > 0):
+ runTimeTicks = float(item.get("RunTimeTicks", "0"))
+ if (runTimeTicks > 0):
+ playBackPos = int(((playBackTicks / 1000) / 10000) / 60)
+ list_item.setProperty('ResumeTime', str(playBackPos))
+
+ percentage = int((playBackTicks / runTimeTicks) * 100.0)
+ list_item.setProperty("complete_percentage", str(percentage))
+
+ video_info_label = {"title": title,
+ "tvshowtitle": tvshowtitle,
+ "year": production_year,
+ "Overlay": overlay,
+ "playcount": playCount}
+
+ list_item.setInfo(type="Video", infoLabels=video_info_label)
+ list_item.setProperty('fanart_image', art['fanart']) # back compat
+ list_item.setProperty('discart', art['discart']) # not avail to setArt
+ list_item.setArt(art)
+ # add count
+ list_item.setProperty("item_index", str(itemCount))
+ itemCount = itemCount + 1
+
+ list_item.setProperty('IsPlayable', 'true')
+
+ totalTime = str(int(float(item.get("RunTimeTicks", "0")) / (10000000 * 60)))
+ list_item.setProperty('TotalTime', str(totalTime))
+
+ list_item.setProperty('id', item_id)
+
+ if simmilarTo is not None:
+ list_item.setProperty('suggested_from_watching', simmilarTo)
+
+ if select_action == "1":
+ playurl = "plugin://plugin.video.embycon/?item_id=" + item_id + '&mode=PLAY'
+ elif select_action == "0":
+ playurl = "plugin://plugin.video.embycon/?item_id=" + item_id + '&mode=SHOW_MENU'
+
+ itemTupple = (playurl, list_item, False)
+ listItems.append(itemTupple)
+
+ return listItems
+
+
+def getWidgetContent(handle, params):
+ log.debug("getWigetContent Called" + str(params))
+
+ type = params.get("type")
+ if (type == None):
+ log.error("getWigetContent type not set")
+ return
+
+ itemsUrl = ("{server}/emby/Users/{userid}/Items" +
+ "?Limit={ItemLimit}" +
+ "&format=json" +
+ "&ImageTypeLimit=1" +
+ "&IsMissing=False")
+
+ if (type == "recent_movies"):
+ xbmcplugin.setContent(handle, 'movies')
+ itemsUrl += ("&Recursive=true" +
+ "&SortBy=DateCreated" +
+ "&SortOrder=Descending" +
+ "&Filters={IsUnplayed,}IsNotFolder" +
+ "&IsVirtualUnaired=false" +
+ "&IsMissing=False" +
+ "&IncludeItemTypes=Movie")
+ elif (type == "inprogress_movies"):
+ xbmcplugin.setContent(handle, 'movies')
+ itemsUrl += ("&Recursive=true" +
+ "&SortBy=DatePlayed" +
+ "&SortOrder=Descending" +
+ "&Filters=IsResumable" +
+ "&IsVirtualUnaired=false" +
+ "&IsMissing=False" +
+ "&IncludeItemTypes=Movie")
+ elif (type == "random_movies"):
+ xbmcplugin.setContent(handle, 'movies')
+ watched = params.get("watched", "") == "true"
+ if watched:
+ itemsUrl += "&Filters=IsPlayed,IsNotFolder"
+ else:
+ itemsUrl += "&Filters={IsUnplayed,}IsNotFolder"
+ itemsUrl += ("&Recursive=true" +
+ "&SortBy=Random" +
+ "&SortOrder=Descending" +
+ "&IsVirtualUnaired=false" +
+ "&IsMissing=False" +
+ "&IncludeItemTypes=Movie")
+ elif (type == "recent_episodes"):
+ xbmcplugin.setContent(handle, 'episodes')
+ itemsUrl += ("&Recursive=true" +
+ "&SortBy=DateCreated" +
+ "&SortOrder=Descending" +
+ "&Filters={IsUnplayed,}IsNotFolder" +
+ "&IsVirtualUnaired=false" +
+ "&IsMissing=False" +
+ "&IncludeItemTypes=Episode")
+ elif (type == "inprogress_episodes"):
+ xbmcplugin.setContent(handle, 'episodes')
+ itemsUrl += ("&Recursive=true" +
+ "&SortBy=DatePlayed" +
+ "&SortOrder=Descending" +
+ "&Filters=IsResumable" +
+ "&IsVirtualUnaired=false" +
+ "&IsMissing=False" +
+ "&IncludeItemTypes=Episode")
+ elif (type == "nextup_episodes"):
+ xbmcplugin.setContent(handle, 'episodes')
+ itemsUrl = ("{server}/emby/Shows/NextUp" +
+ "?Limit={ItemLimit}"
+ "&userid={userid}" +
+ "&Recursive=true" +
+ "&format=json" +
+ "&ImageTypeLimit=1")
+
+ listItems = populateWidgetItems(itemsUrl)
+
+ xbmcplugin.addDirectoryItems(handle, listItems)
+ xbmcplugin.endOfDirectory(handle, cacheToDisc=False)
+
diff --git a/plugin.video.embycon/resources/settings.xml b/plugin.video.embycon/resources/settings.xml
index 4bb7a5a..301caf6 100644
--- a/plugin.video.embycon/resources/settings.xml
+++ b/plugin.video.embycon/resources/settings.xml
@@ -13,7 +13,7 @@
<setting id="deviceName" type="text" label="30016" default="EmbyCon" visible="true" enable="true" />
</category>
<category label="30207">
- <setting id="playback_type" type="enum" label="30206" lvalues="30209|30210|30211" default="1" />
+ <setting id="playback_type" type="select" label="30206" lvalues="30209|30210|30211" default="1" />
<setting label="30209" type="lsep"/>
<setting type="sep" />
<setting id="smbusername" type="text" label="30007" default="" enable="true" visible="true"/>
@@ -21,13 +21,17 @@
<setting label="30211" type="lsep"/>
<setting type="sep" />
<setting id="playback_bitrate" type="slider" label="30208" default="6000" range="400,100,10000" option="int" visible="true"/>
- <setting id="playback_max_width" type="enum" label="30212" lvalues="640x|720x|1024x|1280x|1440x|1600x|1920x|2600x|4096x" default="6" visible="true"/>
+ <setting id="playback_max_width" type="select" label="30212" values="640|720|1024|1280|1440|1600|1920|2600|4096" default="1920" visible="true"/>
<setting id="playback_video_force_8" type="bool" label="30213" default="false" visible="true" enable="true"/>
+ <setting label="30238" type="lsep"/>
+ <setting type="sep" />
+ <setting id="h265_action" type="select" label="30236" lvalues="30129|30210|30211" default="0" />
</category>
<category label="30214">
<setting label="30215" type="lsep"/>
<setting type="sep" />
<setting id="promptPlayNextEpisodePercentage" type="slider" label="30218" default="100" range="5,1,100" option="int" visible="true"/>
+ <setting id="promptPlayNextEpisodePercentage_prompt" type="bool" label="30219" default="true" visible="true" enable="true" />
<setting id="promptDeleteEpisodePercentage" type="slider" label="30217" default="100" range="5,1,100" option="int" visible="true"/>
<setting id="promptDeleteMoviePercentage" type="slider" label="30220" default="100" range="5,1,100" option="int" visible="true"/>
<setting label="30121" type="lsep"/>
@@ -46,6 +50,8 @@
<setting id="include_people" type="bool" label="30183" default="false" visible="true" enable="true" />
<setting id="flatten_single_season" type="bool" label="30020" default="true" visible="true" enable="true" />
<setting id="show_x_filtered_items" type="slider" label="30018" default="20" range="5,1,100" option="int" visible="true"/>
+ <setting id="show_latest_unplayed" type="bool" label="30027" default="false" visible="true" enable="true" />
+ <setting id="widget_select_action" type="enum" label="30026" lvalues="menu|play" default="0" visible="true"/>
<setting id="episode_name_format" type="text" default="{SeriesName} - s{SeasonIndex}e{EpisodeIndex} - {ItemName}" label="30019" />
</category>
<category label="30022"> <!-- Advanced -->
diff --git a/plugin.video.embycon/resources/skins/default/720p/ActionMenu.xml b/plugin.video.embycon/resources/skins/default/720p/ActionMenu.xml
new file mode 100644
index 0000000..11daa26
--- /dev/null
+++ b/plugin.video.embycon/resources/skins/default/720p/ActionMenu.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<window id="3301" type="dialog">
+ <defaultcontrol always="true">3000</defaultcontrol>
+ <zorder>2</zorder>
+ <coordinates>
+ <system>1</system>
+ <left>450</left>
+ <top>200</top>
+ </coordinates>
+ <controls>
+
+ <control type="image" id="3010">
+ <left>0</left>
+ <top>0</top>
+ <width>380</width>
+ <height>300</height>
+ <texture border="40">bg.png</texture>
+ </control>
+
+ <control type="list" id="3000">
+ <left>10</left>
+ <top>10</top>
+ <width>360</width>
+ <!--<height>400</height>-->
+ <height max="780">auto</height>
+ <itemlayout width="360" height="50">
+ <control type="image">
+ <left>0</left>
+ <top>0</top>
+ <width>360</width>
+ <height>45</height>
+ <texture border="1" colordiffuse="ff161616">white.png</texture>
+ </control>
+ <control type="textbox">
+ <width>360</width>
+ <left>0</left>
+ <top>5</top>
+ <height>45</height>
+ <label>$INFO[ListItem.Label]</label>
+ <textcolor>99FFFFFF</textcolor>
+ <font>font14</font>
+ <align>center</align>
+ </control>
+ </itemlayout>
+ <focusedlayout width="360" height="50">
+ <control type="image">
+ <left>0</left>
+ <top>0</top>
+ <width>360</width>
+ <height>45</height>
+ <texture border="1" colordiffuse="ff525252">white.png</texture>
+ </control>
+ <control type="textbox">
+ <width>360</width>
+ <left>0</left>
+ <top>5</top>
+ <height>45</height>
+ <label>$INFO[ListItem.Label]</label>
+ <textcolor>FFFFFFFF</textcolor>
+ <font>font14</font>
+ <align>center</align>
+ </control>
+ </focusedlayout>
+ </control>
+
+ </controls>
+</window> \ No newline at end of file
diff --git a/plugin.video.embycon/resources/skins/default/720p/ResumeDialog.xml b/plugin.video.embycon/resources/skins/default/720p/ResumeDialog.xml
index 9ff6bad..9f1116a 100644
--- a/plugin.video.embycon/resources/skins/default/720p/ResumeDialog.xml
+++ b/plugin.video.embycon/resources/skins/default/720p/ResumeDialog.xml
@@ -7,7 +7,6 @@
<left>450</left>
<top>280</top>
</coordinates>
- <include>dialogeffect</include>
<controls>
<control type="image">
diff --git a/plugin.video.embycon/resources/skins/skin.estuary/xml/Home-17.1.xml b/plugin.video.embycon/resources/skins/skin.estuary/xml/Home-17.1.xml
index ef46639..cb9b540 100644
--- a/plugin.video.embycon/resources/skins/skin.estuary/xml/Home-17.1.xml
+++ b/plugin.video.embycon/resources/skins/skin.estuary/xml/Home-17.1.xml
@@ -52,19 +52,19 @@
<control type="grouplist" id="3001">
<include>WidgetGroupListCommon</include>
<include content="WidgetListPoster" condition="true">
- <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&type=recent_movies"/>
+ <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&amp;type=recent_movies&amp;reload=$INFO[Window(Home).Property(plugin.video.embycon-embycon_widget_reload)]"/>
<param name="widget_header" value="Recently Added"/>
<param name="widget_target" value="videos"/>
<param name="list_id" value="3800"/>
</include>
<include content="WidgetListPoster" condition="true">
- <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&type=inprogress_movies"/>
+ <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&amp;type=inprogress_movies&amp;reload=$INFO[Window(Home).Property(plugin.video.embycon-embycon_widget_reload)]"/>
<param name="widget_header" value="In Progress"/>
<param name="widget_target" value="videos"/>
<param name="list_id" value="3900"/>
</include>
<include content="WidgetListPoster" condition="true">
- <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&type=random_movies"/>
+ <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&amp;type=random_movies&amp;reload=$INFO[Window(Home).Property(plugin.video.embycon-embycon_widget_reload)]"/>
<param name="widget_header" value="Random"/>
<param name="widget_target" value="videos"/>
<param name="list_id" value="3100"/>
@@ -79,19 +79,19 @@
<control type="grouplist" id="4001">
<include>WidgetGroupListCommon</include>
<include content="WidgetListEpisodes" condition="true">
- <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&type=recent_episodes"/>
+ <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&amp;type=recent_episodes&amp;reload=$INFO[Window(Home).Property(plugin.video.embycon-embycon_widget_reload)]"/>
<param name="widget_header" value="Recently Added"/>
<param name="widget_target" value="videos"/>
<param name="list_id" value="4900"/>
</include>
<include content="WidgetListEpisodes" condition="true">
- <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&type=inprogress_episodes"/>
+ <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&amp;type=inprogress_episodes&amp;reload=$INFO[Window(Home).Property(plugin.video.embycon-embycon_widget_reload)]"/>
<param name="widget_header" value="In Progress"/>
<param name="widget_target" value="videos"/>
<param name="list_id" value="4100"/>
</include>
<include content="WidgetListEpisodes" condition="true">
- <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&type=nextup_episodes"/>
+ <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&amp;type=nextup_episodes&amp;reload=$INFO[Window(Home).Property(plugin.video.embycon-embycon_widget_reload)]"/>
<param name="widget_header" value="Next Up"/>
<param name="widget_target" value="videos"/>
<param name="list_id" value="4200"/>
diff --git a/plugin.video.embycon/resources/skins/skin.estuary/xml/Home-17.3-elec.xml b/plugin.video.embycon/resources/skins/skin.estuary/xml/Home-17.3-elec.xml
new file mode 100644
index 0000000..cb996ed
--- /dev/null
+++ b/plugin.video.embycon/resources/skins/skin.estuary/xml/Home-17.3-elec.xml
@@ -0,0 +1,1064 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<window>
+ <onunload>ClearProperty(first_load_done, 10000)</onunload>
+ <defaultcontrol>9000</defaultcontrol>
+ <backgroundcolor>background</backgroundcolor>
+ <controls>
+ <control type="button" id="20000">
+ <include>HiddenObject</include>
+ <animation effect="fade" time="300" start="100" end="0">Focus</animation>
+ <onfocus>SetFocus(2000)</onfocus>
+ <onclick>noop</onclick>
+ <visible allowhiddenfocus="true">Control.HasFocus(20000)</visible>
+ </control>
+ <control type="button" id="20001">
+ <include>HiddenObject</include>
+ <animation effect="fade" time="300" start="100" end="0">Focus</animation>
+ <onfocus>SetFocus(2000)</onfocus>
+ <onclick>noop</onclick>
+ <visible allowhiddenfocus="true">Control.HasFocus(20001)</visible>
+ </control>
+ <include>DefaultBackground</include>
+ <control type="multiimage">
+ <depth>DepthBackground</depth>
+ <include>FullScreenDimensions</include>
+ <aspectratio>scale</aspectratio>
+ <fadetime>600</fadetime>
+ <animation effect="zoom" center="auto" end="102,102" time="0" condition="Integer.IsGreater(System.StereoscopicMode,0)">conditional</animation>
+ <animation effect="fade" start="0" end="100" time="400">WindowOpen</animation>
+ <animation effect="fade" start="100" end="0" time="300">WindowClose</animation>
+ <animation effect="fade" time="400">VisibleChange</animation>
+ <imagepath background="true" colordiffuse="bg_overlay">$VAR[HomeFanartVar]</imagepath>
+ <visible>!Player.HasMedia</visible>
+ </control>
+ <control type="group">
+ <animation effect="fade" start="100" end="0" time="200" tween="sine" condition="$EXP[infodialog_active]">Conditional</animation>
+ <control type="group" id="2000">
+ <left>462</left>
+ <animation type="Conditional" condition="Control.IsVisible(20000)" reversible="false">
+ <effect type="slide" end="0,20" time="60" tween="sine" />
+ <effect type="slide" end="0,-20" time="180" tween="sine" delay="80" />
+ </animation>
+ <animation type="Conditional" condition="Control.IsVisible(20001)" reversible="false">
+ <effect type="slide" end="0,-20" time="60" tween="sine" />
+ <effect type="slide" end="0,20" time="180" tween="sine" delay="80" />
+ </animation>
+ <include>OpenClose_Right</include>
+ <!-- Start of Emby Widget Items -->
+ <control type="group" id="3000">
+ <visible>String.IsEqual(Container(9000).ListItem.Property(id),emby_movies)</visible>
+ <include content="Visible_Right_Delayed">
+ <param name="id" value="emby_movies"/>
+ </include>
+ <control type="grouplist" id="3001">
+ <include>WidgetGroupListCommon</include>
+ <include content="WidgetListPoster" condition="true">
+ <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&amp;type=recent_movies&amp;reload=$INFO[Window(Home).Property(plugin.video.embycon-embycon_widget_reload)]"/>
+ <param name="widget_header" value="Recently Added"/>
+ <param name="widget_target" value="videos"/>
+ <param name="list_id" value="3800"/>
+ </include>
+ <include content="WidgetListPoster" condition="true">
+ <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&amp;type=inprogress_movies&amp;reload=$INFO[Window(Home).Property(plugin.video.embycon-embycon_widget_reload)]"/>
+ <param name="widget_header" value="In Progress"/>
+ <param name="widget_target" value="videos"/>
+ <param name="list_id" value="3900"/>
+ </include>
+ <include content="WidgetListPoster" condition="true">
+ <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&amp;type=random_movies&amp;reload=$INFO[Window(Home).Property(plugin.video.embycon-embycon_widget_reload)]"/>
+ <param name="widget_header" value="Random"/>
+ <param name="widget_target" value="videos"/>
+ <param name="list_id" value="3100"/>
+ </include>
+ </control>
+ </control>
+ <control type="group" id="4000">
+ <visible>String.IsEqual(Container(9000).ListItem.Property(id),emby_tvshows)</visible>
+ <include content="Visible_Right_Delayed">
+ <param name="id" value="emby_tvshows"/>
+ </include>
+ <control type="grouplist" id="4001">
+ <include>WidgetGroupListCommon</include>
+ <include content="WidgetListEpisodes" condition="true">
+ <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&amp;type=recent_episodes&amp;reload=$INFO[Window(Home).Property(plugin.video.embycon-embycon_widget_reload)]"/>
+ <param name="widget_header" value="Recently Added"/>
+ <param name="widget_target" value="videos"/>
+ <param name="list_id" value="4900"/>
+ </include>
+ <include content="WidgetListEpisodes" condition="true">
+ <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&amp;type=inprogress_episodes&amp;reload=$INFO[Window(Home).Property(plugin.video.embycon-embycon_widget_reload)]"/>
+ <param name="widget_header" value="In Progress"/>
+ <param name="widget_target" value="videos"/>
+ <param name="list_id" value="4100"/>
+ </include>
+ <include content="WidgetListEpisodes" condition="true">
+ <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&amp;type=nextup_episodes&amp;reload=$INFO[Window(Home).Property(plugin.video.embycon-embycon_widget_reload)]"/>
+ <param name="widget_header" value="Next Up"/>
+ <param name="widget_target" value="videos"/>
+ <param name="list_id" value="4200"/>
+ </include>
+ </control>
+ </control>
+ <!-- End of Emby Widget Items -->
+ <control type="group" id="5000">
+ <visible>String.IsEqual(Container(9000).ListItem.Property(id),movies)</visible>
+ <include content="Visible_Right_Delayed">
+ <param name="id" value="movies"/>
+ </include>
+ <control type="grouplist" id="5001">
+ <include>WidgetGroupListCommon</include>
+ <include content="WidgetListCategories" condition="Library.HasContent(movies)">
+ <param name="content_path" value="library://video/movies/"/>
+ <param name="widget_header" value="$LOCALIZE[31148]"/>
+ <param name="widget_target" value="videos"/>
+ <param name="list_id" value="5900"/>
+ </include>
+ <include content="WidgetListPoster" condition="Library.HasContent(movies)">
+ <param name="content_path" value="special://skin/playlists/inprogress_movies.xsp"/>
+ <param name="widget_header" value="$LOCALIZE[31010]"/>
+ <param name="widget_target" value="videos"/>
+ <param name="list_id" value="5100"/>
+ </include>
+ <include content="WidgetListPoster" condition="Library.HasContent(movies)">
+ <param name="content_path" value="special://skin/playlists/recent_unwatched_movies.xsp"/>
+ <param name="widget_header" value="$LOCALIZE[20386]"/>
+ <param name="widget_target" value="videos"/>
+ <param name="list_id" value="5200"/>
+ </include>
+ <include content="WidgetListPoster" condition="Library.HasContent(movies)">
+ <param name="content_path" value="special://skin/playlists/unwatched_movies.xsp"/>
+ <param name="widget_header" value="$LOCALIZE[31007]"/>
+ <param name="widget_target" value="videos"/>
+ <param name="list_id" value="5300"/>
+ </include>
+ <include content="WidgetListPoster" condition="Library.HasContent(movies)">
+ <param name="content_path" value="special://skin/playlists/random_movies.xsp"/>
+ <param name="widget_header" value="$LOCALIZE[31006]"/>
+ <param name="widget_target" value="videos"/>
+ <param name="list_id" value="5400"/>
+ </include>
+ <include content="WidgetListCategories" condition="Library.HasContent(movies)">
+ <param name="content_path" value="videodb://movies/genres/"/>
+ <param name="widget_header" value="$LOCALIZE[135]"/>
+ <param name="widget_target" value="videos"/>
+ <param name="list_id" value="5500"/>
+ <param name="icon" value="$VAR[WidgetGenreIconVar]"/>
+ <param name="icon_height" value="70"/>
+ </include>
+ <include content="WidgetListPoster" condition="Library.HasContent(movies)">
+ <param name="content_path" value="videodb://movies/sets/"/>
+ <param name="widget_header" value="$LOCALIZE[31075]"/>
+ <param name="widget_target" value="videos"/>
+ <param name="sortby" value="random"/>
+ <param name="list_id" value="5600"/>
+ </include>
+ </control>
+ <include content="ImageWidget" condition="!Library.HasContent(movies)">
+ <param name="text_label" value="$LOCALIZE[31104]" />
+ <param name="button_label" value="$LOCALIZE[31110]" />
+ <param name="button_onclick" value="ActivateWindow(videos,files,return)"/>
+ <param name="button_id" value="5500"/>
+ <param name="button2_onclick" value="Skin.SetBool(HomeMenuNoMovieButton)"/>
+ </include>
+ </control>
+ <control type="group" id="6000">
+ <visible>String.IsEqual(Container(9000).ListItem.Property(id),tvshows)</visible>
+ <include content="Visible_Right_Delayed">
+ <param name="id" value="tvshows"/>
+ </include>
+ <control type="grouplist" id="6001">
+ <include>WidgetGroupListCommon</include>
+ <include content="WidgetListCategories" condition="Library.HasContent(tvshows)">
+ <param name="content_path" value="library://video/tvshows/"/>
+ <param name="widget_header" value="$LOCALIZE[31148]"/>
+ <param name="widget_target" value="videos"/>
+ <param name="list_id" value="6900"/>
+ </include>
+ <include content="WidgetListPoster" condition="Library.HasContent(tvshows)">
+ <param name="content_path" value="videodb://inprogresstvshows"/>
+ <param name="sortby" value="lastplayed"/>
+ <param name="sortorder" value="descending"/>
+ <param name="widget_header" value="$LOCALIZE[626]"/>
+ <param name="widget_target" value="videos"/>
+ <param name="list_id" value="6100"/>
+ </include>
+ <include content="WidgetListEpisodes" condition="Library.HasContent(tvshows)">
+ <param name="content_path" value="special://skin/playlists/recent_unwatched_episodes.xsp"/>
+ <param name="widget_header" value="$LOCALIZE[20387]"/>
+ <param name="widget_target" value="videos"/>
+ <param name="list_id" value="6200"/>
+ </include>
+ <include content="WidgetListPoster" condition="Library.HasContent(tvshows)">
+ <param name="content_path" value="special://skin/playlists/unwatched_tvshows.xsp"/>
+ <param name="widget_header" value="$LOCALIZE[31122]"/>
+ <param name="widget_target" value="videos"/>
+ <param name="list_id" value="6300"/>
+ </include>
+ <include content="WidgetListCategories" condition="Library.HasContent(tvshows)">
+ <param name="content_path" value="videodb://tvshows/genres/"/>
+ <param name="widget_header" value="$LOCALIZE[135]"/>
+ <param name="widget_target" value="videos"/>
+ <param name="list_id" value="6400"/>
+ <param name="icon" value="$VAR[WidgetGenreIconVar]"/>
+ <param name="icon_height" value="70"/>
+ </include>
+ <include content="WidgetListCategories" condition="Library.HasContent(tvshows)">
+ <param name="content_path" value="videodb://tvshows/studios/"/>
+ <param name="widget_header" value="$LOCALIZE[20388]"/>
+ <param name="widget_target" value="videos"/>
+ <param name="list_id" value="6500"/>
+ <param name="icon" value="$VAR[WidgetStudioIconVar]"/>
+ <param name="icon_height" value="70"/>
+ </include>
+ </control>
+ <include content="ImageWidget" condition="!Library.HasContent(tvshows)">
+ <param name="text_label" value="$LOCALIZE[31104]" />
+ <param name="button_label" value="$LOCALIZE[31110]" />
+ <param name="button_onclick" value="ActivateWindow(videos,files,return)"/>
+ <param name="button_id" value="6400"/>
+ <param name="button2_onclick" value="Skin.SetBool(HomeMenuNoTVShowButton)"/>
+ </include>
+ </control>
+ <control type="group" id="7000">
+ <visible>String.IsEqual(Container(9000).ListItem.Property(id),music)</visible>
+ <include content="Visible_Right_Delayed">
+ <param name="id" value="music"/>
+ </include>
+ <control type="grouplist" id="7001">
+ <include>WidgetGroupListCommon</include>
+ <include content="WidgetListCategories" condition="Library.HasContent(music)">
+ <param name="content_path" value="library://music/"/>
+ <param name="widget_header" value="$LOCALIZE[31148]"/>
+ <param name="widget_target" value="music"/>
+ <param name="list_id" value="7900"/>
+ </include>
+ <include content="WidgetListSquare" condition="Library.HasContent(music)">
+ <param name="content_path" value="musicdb://recentlyplayedalbums"/>
+ <param name="widget_header" value="$LOCALIZE[517]"/>
+ <param name="widget_target" value="music"/>
+ <param name="list_id" value="7100"/>
+ <param name="fallback_icon" value="DefaultMusicAlbums.png"/>
+ </include>
+ <include content="WidgetListSquare" condition="Library.HasContent(music)">
+ <param name="content_path" value="musicdb://recentlyaddedalbums/"/>
+ <param name="widget_header" value="$LOCALIZE[359]"/>
+ <param name="widget_target" value="music"/>
+ <param name="list_id" value="7200"/>
+ <param name="fallback_icon" value="DefaultMusicAlbums.png"/>
+ </include>
+ <include content="WidgetListSquare" condition="Library.HasContent(music)">
+ <param name="content_path" value="special://skin/playlists/random_albums.xsp"/>
+ <param name="widget_header" value="$LOCALIZE[31012]"/>
+ <param name="widget_target" value="music"/>
+ <param name="list_id" value="7300"/>
+ <param name="fallback_icon" value="DefaultMusicAlbums.png"/>
+ </include>
+ <include content="WidgetListSquare" condition="Library.HasContent(music)">
+ <param name="content_path" value="special://skin/playlists/random_artists.xsp"/>
+ <param name="widget_header" value="$LOCALIZE[31013]"/>
+ <param name="widget_target" value="music"/>
+ <param name="list_id" value="7400"/>
+ <param name="fallback_icon" value="DefaultMusicArtists.png"/>
+ </include>
+ <include content="WidgetListSquare" condition="Library.HasContent(music)">
+ <param name="content_path" value="special://skin/playlists/unplayed_albums.xsp"/>
+ <param name="widget_header" value="$LOCALIZE[31014]"/>
+ <param name="widget_target" value="music"/>
+ <param name="list_id" value="7500"/>
+ <param name="fallback_icon" value="DefaultMusicAlbums.png"/>
+ </include>
+ <include content="WidgetListSquare" condition="Library.HasContent(music)">
+ <param name="content_path" value="special://skin/playlists/mostplayed_albums.xsp"/>
+ <param name="widget_header" value="$LOCALIZE[31011]"/>
+ <param name="widget_target" value="music"/>
+ <param name="list_id" value="7600"/>
+ <param name="fallback_icon" value="DefaultMusicAlbums.png"/>
+ <param name="sortby" value="playcount"/>
+ <param name="sortorder" value="descending"/>
+ </include>
+ </control>
+ <include content="ImageWidget" condition="!Library.HasContent(music)">
+ <param name="text_label" value="$LOCALIZE[31104]" />
+ <param name="button_label" value="$LOCALIZE[31110]" />
+ <param name="button_onclick" value="ActivateWindow(music,files)"/>
+ <param name="button_id" value="7600"/>
+ <param name="button2_onclick" value="Skin.SetBool(HomeMenuNoMusicButton)"/>
+ </include>
+ </control>
+ <control type="group" id="8000">
+ <visible>String.IsEqual(Container(9000).ListItem.Property(id),addons)</visible>
+ <include content="Visible_Right_Delayed">
+ <param name="id" value="addons"/>
+ </include>
+ <control type="grouplist" id="8001">
+ <include>WidgetGroupListCommon</include>
+ <include content="WidgetListCategories">
+ <param name="widget_header" value="$LOCALIZE[31148]"/>
+ <param name="list_id" value="8900"/>
+ <param name="visible" value="Integer.IsGreater(Container(8100).NumItems,0) | Integer.IsGreater(Container(8200).NumItems,0) | Integer.IsGreater(Container(8300).NumItems,0) | Integer.IsGreater(Container(8400).NumItems,0) | Integer.IsGreater(Container(8500).NumItems,0)"/>
+ <param name="addon_submenu" value="true"/>
+ </include>
+ <include content="WidgetListSquare">
+ <param name="content_path" value="addons://sources/video/"/>
+ <param name="widget_header" value="$LOCALIZE[1037]"/>
+ <param name="widget_target" value="videos"/>
+ <param name="sortby" value="lastused"/>
+ <param name="sortorder" value="descending"/>
+ <param name="list_id" value="8100"/>
+ <param name="fallback_icon" value="DefaultAddon.png"/>
+ </include>
+ <include content="WidgetListSquare">
+ <param name="content_path" value="addons://sources/audio/"/>
+ <param name="widget_header" value="$LOCALIZE[1038]"/>
+ <param name="widget_target" value="music"/>
+ <param name="sortby" value="lastused"/>
+ <param name="sortorder" value="descending"/>
+ <param name="list_id" value="8200"/>
+ <param name="fallback_icon" value="DefaultAddon.png"/>
+ </include>
+ <include content="WidgetListSquare">
+ <param name="content_path" value="addons://sources/executable/"/>
+ <param name="widget_header" value="$LOCALIZE[1043]"/>
+ <param name="widget_target" value="programs"/>
+ <param name="sortby" value="lastused"/>
+ <param name="sortorder" value="descending"/>
+ <param name="list_id" value="8300"/>
+ <param name="fallback_icon" value="DefaultAddon.png"/>
+ </include>
+ <include content="WidgetListSquare" condition="System.Platform.Android">
+ <param name="content_path" value="androidapp://sources/apps/"/>
+ <param name="widget_header" value="$LOCALIZE[20244]"/>
+ <param name="widget_target" value="programs"/>
+ <param name="sortby" value="lastused"/>
+ <param name="sortorder" value="descending"/>
+ <param name="list_id" value="8400"/>
+ <param name="fallback_icon" value="DefaultAddon.png"/>
+ </include>
+ <include content="WidgetListSquare">
+ <param name="content_path" value="addons://sources/image/"/>
+ <param name="widget_header" value="$LOCALIZE[1039]"/>
+ <param name="widget_target" value="pictures"/>
+ <param name="sortby" value="lastused"/>
+ <param name="sortorder" value="descending"/>
+ <param name="list_id" value="8500"/>
+ </include>
+ </control>
+ <include content="ImageWidget">
+ <param name="text_label" value="$LOCALIZE[31119]" />
+ <param name="button_label" value="$LOCALIZE[31118]" />
+ <param name="button_onclick" value="ActivateWindow(addonbrowser)"/>
+ <param name="button_id" value="8600"/>
+ <param name="visible" value="!Integer.IsGreater(Container(8001).NumItems,0)"/>
+ <param name="button2_onclick" value="Skin.SetBool(HomeMenuNoProgramsButton)"/>
+ </include>
+ </control>
+ <control type="group" id="11000">
+ <visible>String.IsEqual(Container(9000).ListItem.Property(id),video)</visible>
+ <include content="Visible_Right_Delayed">
+ <param name="id" value="video"/>
+ </include>
+ <control type="grouplist" id="11001">
+ <include>WidgetGroupListCommon</include>
+ <include content="WidgetListCategories">
+ <param name="content_path" value="library://video/"/>
+ <param name="widget_header" value="$LOCALIZE[31148]"/>
+ <param name="widget_target" value="videos"/>
+ <param name="list_id" value="11900"/>
+ </include>
+ <include content="WidgetListCategories">
+ <param name="content_path" value="sources://video/"/>
+ <param name="widget_header" value="$LOCALIZE[20094]"/>
+ <param name="widget_target" value="videos"/>
+ <param name="list_id" value="11100"/>
+ </include>
+ <include content="WidgetListCategories">
+ <param name="content_path" value="special://videoplaylists/"/>
+ <param name="widget_header" value="$LOCALIZE[136]"/>
+ <param name="widget_target" value="videos"/>
+ <param name="list_id" value="11200"/>
+ <param name="icon" value="DefaultPlaylist.png"/>
+ </include>
+ </control>
+ <include content="ImageWidget">
+ <param name="text_label" value="$LOCALIZE[31105]" />
+ <param name="button_label" value="$LOCALIZE[31110]" />
+ <param name="button_onclick" value="ActivateWindow(videos,root)"/>
+ <param name="button_id" value="11300"/>
+ <param name="visible" value="!Integer.IsGreater(Container(11001).NumItems,0)"/>
+ <param name="button2_onclick" value="Skin.SetBool(HomeMenuNoVideosButton)"/>
+ </include>
+ </control>
+ <control type="group" id="12000">
+ <visible>String.IsEqual(Container(9000).ListItem.Property(id),livetv)</visible>
+ <include content="Visible_Right_Delayed">
+ <param name="id" value="livetv"/>
+ </include>
+ <control type="grouplist" id="12001">
+ <include>WidgetGroupListCommon</include>
+ <control type="grouplist" id="12855">
+ <height>390</height>
+ <left>0</left>
+ <right>0</right>
+ <top>36</top>
+ <orientation>horizontal</orientation>
+ <visible>PVR.IsRecordingTV | PVR.HasNonRecordingTVTimer</visible>
+ <align>center</align>
+ <control type="group">
+ <width>674</width>
+ <visible>PVR.IsRecordingTV</visible>
+ <include content="PVRWidget">
+ <param name="icon" value="$INFO[PVR.TVNowRecordingChannelIcon]" />
+ <param name="header" value="$LOCALIZE[19158]" />
+ <param name="label1" value="$INFO[PVR.TVNowRecordingDateTime]" />
+ <param name="label2" value="$INFO[PVR.TVNowRecordingTitle][CR][COLOR=grey]$INFO[PVR.TVNowRecordingChannel][/COLOR]" />
+ </include>
+ </control>
+ <control type="group">
+ <width>674</width>
+ <visible>PVR.HasNonRecordingTVTimer</visible>
+ <include content="PVRWidget">
+ <param name="icon" value="$INFO[PVR.TVNextRecordingChannelIcon]" />
+ <param name="header" value="$LOCALIZE[19157]" />
+ <param name="label1" value="$INFO[PVR.TVNextRecordingDateTime]" />
+ <param name="label2" value="$INFO[PVR.TVNextRecordingTitle][CR][COLOR=grey]$INFO[PVR.TVNextRecordingChannel][/COLOR]" />
+ </include>
+ </control>
+ </control>
+ <include content="WidgetListCategories" condition="System.HasPVRAddon">
+ <param name="widget_header" value="$LOCALIZE[31148]"/>
+ <param name="list_id" value="12900"/>
+ <param name="pvr_submenu" value="true"/>
+ <param name="pvr_type" value="TV"/>
+ </include>
+ <include content="WidgetListChannels" condition="System.HasPVRAddon">
+ <param name="content_path" value="pvr://channels/tv/*?view=lastplayed"/>
+ <param name="sortby" value="lastplayed"/>
+ <param name="sortorder" value="descending"/>
+ <param name="widget_header" value="$LOCALIZE[31016]"/>
+ <param name="widget_target" value="pvr"/>
+ <param name="list_id" value="12200"/>
+ </include>
+ <include content="WidgetListChannels" condition="System.HasPVRAddon">
+ <param name="content_path" value="pvr://recordings/tv/active?view=flat"/>
+ <param name="sortby" value="date"/>
+ <param name="sortorder" value="descending"/>
+ <param name="widget_header" value="$LOCALIZE[31015]"/>
+ <param name="widget_target" value="pvr"/>
+ <param name="list_id" value="12300"/>
+ <param name="label" value="$INFO[ListItem.ChannelName]"/>
+ <param name="label2" value="$INFO[ListItem.Title]$INFO[ListItem.EpisodeName, (,)]"/>
+ </include>
+ </control>
+ <include content="ImageWidget" condition="!System.HasPVRAddon">
+ <param name="text_label" value="$LOCALIZE[31143]" />
+ <param name="button_label" value="$LOCALIZE[31144]" />
+ <param name="button_onclick" value="ActivateWindow(addonbrowser,addons://user/xbmc.pvrclient,return)"/>
+ <param name="button_id" value="12400"/>
+ <param name="button2_onclick" value="Skin.SetBool(HomeMenuNoTVButton)"/>
+ </include>
+ </control>
+ <control type="group" id="13000">
+ <visible>String.IsEqual(Container(9000).ListItem.Property(id),radio)</visible>
+ <include content="Visible_Right_Delayed">
+ <param name="id" value="radio"/>
+ </include>
+ <control type="grouplist" id="13001">
+ <include>WidgetGroupListCommon</include>
+ <control type="grouplist" id="13855">
+ <height>390</height>
+ <left>25</left>
+ <top>36</top>
+ <orientation>horizontal</orientation>
+ <align>right</align>
+ <width>1360</width>
+ <visible>PVR.IsRecordingRadio | PVR.HasNonRecordingRadioTimer</visible>
+ <control type="group">
+ <width>680</width>
+ <visible>PVR.IsRecordingRadio</visible>
+ <include content="PVRWidget">
+ <param name="icon" value="$INFO[PVR.RadioNowRecordingChannelIcon]" />
+ <param name="header" value="$LOCALIZE[19158]" />
+ <param name="label1" value="$INFO[PVR.RadioNowRecordingDateTime]" />
+ <param name="label2" value="$INFO[PVR.RadioNowRecordingTitle][CR][COLOR=grey]$INFO[PVR.RadioNowRecordingChannel][/COLOR]" />
+ </include>
+ </control>
+ <control type="group">
+ <visible>PVR.HasNonRecordingRadioTimer</visible>
+ <width>680</width>
+ <include content="PVRWidget">
+ <param name="icon" value="$INFO[PVR.RadioNextRecordingChannelIcon]" />
+ <param name="header" value="$LOCALIZE[19157]" />
+ <param name="label1" value="$INFO[PVR.RadioNextRecordingDateTime]" />
+ <param name="label2" value="$INFO[PVR.RadioNextRecordingTitle][CR][COLOR=grey]$INFO[PVR.RadioNextRecordingChannel][/COLOR]" />
+ </include>
+ </control>
+ </control>
+ <include content="WidgetListCategories" condition="System.HasPVRAddon">
+ <param name="widget_header" value="$LOCALIZE[31148]"/>
+ <param name="list_id" value="13900"/>
+ <param name="pvr_submenu" value="true"/>
+ <param name="pvr_type" value="Radio"/>
+ </include>
+ <include content="WidgetListChannels" condition="System.HasPVRAddon">
+ <param name="content_path" value="pvr://channels/radio/*?view=lastplayed"/>
+ <param name="sortby" value="lastplayed"/>
+ <param name="sortorder" value="descending"/>
+ <param name="widget_header" value="$LOCALIZE[31018]"/>
+ <param name="widget_target" value="files"/>
+ <param name="list_id" value="13200"/>
+ </include>
+ <include content="WidgetListChannels" condition="System.HasPVRAddon">
+ <param name="content_path" value="pvr://recordings/radio/active?view=flat"/>
+ <param name="sortby" value="date"/>
+ <param name="sortorder" value="descending"/>
+ <param name="widget_header" value="$LOCALIZE[31015]"/>
+ <param name="widget_target" value="pvr"/>
+ <param name="list_id" value="13300"/>
+ <param name="label" value="$INFO[ListItem.ChannelName]"/>
+ <param name="label2" value="$INFO[ListItem.Title]$INFO[ListItem.EpisodeName, (,)]"/>
+ </include>
+ </control>
+ <include content="ImageWidget" condition="!System.HasPVRAddon">
+ <param name="text_label" value="$LOCALIZE[31143]" />
+ <param name="button_label" value="$LOCALIZE[31144]" />
+ <param name="button_onclick" value="ActivateWindow(addonbrowser,addons://user/xbmc.pvrclient,return)"/>
+ <param name="button_id" value="13400"/>
+ <param name="button2_onclick" value="Skin.SetBool(HomeMenuNoRadioButton)"/>
+ </include>
+ </control>
+ <control type="group" id="14000">
+ <visible>String.IsEqual(Container(9000).ListItem.Property(id),favorites)</visible>
+ <include content="Visible_Right_Delayed">
+ <param name="id" value="favorites"/>
+ </include>
+ <control type="panel" id="14100">
+ <left>65</left>
+ <top>0</top>
+ <right>0</right>
+ <bottom>0</bottom>
+ <onleft>9000</onleft>
+ <onright>9000</onright>
+ <onup>14100</onup>
+ <ondown>14100</ondown>
+ <onclick>$INFO[ListItem.FileNameAndPath]</onclick>
+ <preloaditems>2</preloaditems>
+ <scrolltime tween="cubic" easing="out">500</scrolltime>
+ <orientation>vertical</orientation>
+ <visible>Integer.IsGreater(Container(14100).NumItems,0) | Container(14100).IsUpdating</visible>
+ <itemlayout width="330" height="396">
+ <control type="group">
+ <top>130</top>
+ <include content="InfoWallMusicLayout">
+ <param name="fallback_image" value="DefaultFavourites.png" />
+ <param name="focused" value="false" />
+ </include>
+ </control>
+ </itemlayout>
+ <focusedlayout width="330" height="396">
+ <control type="group">
+ <depth>DepthContentPopout</depth>
+ <top>130</top>
+ <animation effect="zoom" start="100" end="110" time="200" tween="sine" easing="inout" center="170,320">Focus</animation>
+ <animation effect="zoom" start="110" end="100" time="200" tween="sine" easing="inout" center="170,320">UnFocus</animation>
+ <include content="InfoWallMusicLayout">
+ <param name="fallback_image" value="DefaultFavourites.png" />
+ <param name="focused" value="true" />
+ </include>
+ </control>
+ </focusedlayout>
+ <content>favourites://</content>
+ </control>
+ <include content="ImageWidget">
+ <param name="text_label" value="$LOCALIZE[31025]" />
+ <param name="button_label" value="$LOCALIZE[31116]" />
+ <param name="button_onclick" value=""/>
+ <param name="button_id" value="5500"/>
+ <param name="visible" value="!Integer.IsGreater(Container(14100).NumItems,0) + !Container(14100).IsUpdating"/>
+ <param name="visible_1" value="false"/>
+ <param name="button2_onclick" value="Skin.SetBool(HomeMenuNoFavButton)"/>
+ </include>
+ </control>
+ <control type="group" id="15000">
+ <visible>String.IsEqual(Container(9000).ListItem.Property(id),weather)</visible>
+ <include content="Visible_Right_Delayed">
+ <param name="id" value="weather"/>
+ </include>
+ <control type="grouplist" id="15001">
+ <include>WidgetGroupListCommon</include>
+ <control type="group" id="16678">
+ <description>Weather info</description>
+ <left>68</left>
+ <right>70</right>
+ <top>102</top>
+ <height>300</height>
+ <visible>!String.IsEmpty(Weather.plugin)</visible>
+ <control type="image">
+ <bottom>90</bottom>
+ <width>100%</width>
+ <texture border="21">dialogs/dialog-bg.png</texture>
+ </control>
+ <control type="label">
+ <left>840</left>
+ <top>60</top>
+ <aligny>center</aligny>
+ <height>24</height>
+ <right>60</right>
+ <align>right</align>
+ <font>font30_title</font>
+ <label>$INFO[Weather.Location]</label>
+ </control>
+ <control type="label">
+ <left>840</left>
+ <top>120</top>
+ <aligny>center</aligny>
+ <height>24</height>
+ <right>60</right>
+ <align>right</align>
+ <font>font14</font>
+ <label>$INFO[Weather.Conditions,, ∙ ]$INFO[Weather.Temperature]</label>
+ </control>
+ <control type="grouplist">
+ <top>50</top>
+ <left>50</left>
+ <right>20</right>
+ <orientation>horizontal</orientation>
+ <align>left</align>
+ <itemgap>-110</itemgap>
+ <include content="WeatherIcon" condition="!String.IsEmpty(Weather.Plugin)">
+ <param name="label" value="Window(weather).Property(Current.Wind)" />
+ <param name="texture" value="icons/weather/wind.png" />
+ <param name="header" value="404" />
+ </include>
+ <include content="WeatherIcon" condition="!String.IsEmpty(Weather.Plugin)">
+ <param name="label" value="Window(weather).Property(Current.Humidity)" />
+ <param name="texture" value="icons/weather/humidity.png" />
+ <param name="header" value="406" />
+ </include>
+ <include content="WeatherIcon" condition="!String.IsEmpty(Weather.Plugin)">
+ <param name="label" value="Window(weather).Property(Current.Precipitation)" />
+ <param name="texture" value="icons/weather/rain.png" />
+ <param name="header" value="33021" />
+ </include>
+ <include content="WeatherIcon" condition="!String.IsEmpty(Weather.Plugin)">
+ <param name="label" value="Window(weather).Property(Today.Sunrise)" />
+ <param name="texture" value="icons/weather/sunrise.png" />
+ <param name="header" value="405" />
+ </include>
+ <include content="WeatherIcon" condition="!String.IsEmpty(Weather.Plugin)">
+ <param name="label" value="Window(weather).Property(Today.Sunset)" />
+ <param name="texture" value="icons/weather/sunset.png" />
+ <param name="header" value="403" />
+ </include>
+ </control>
+ </control>
+ <include content="WeatherWidget" condition="!String.IsEmpty(Weather.Plugin)">
+ <param name="content_include" value="DailyItems" />
+ <param name="list_id" value="15200" />
+ <param name="widget_header" value="$LOCALIZE[31019]"/>
+ <param name="visible" value="!String.IsEmpty(Window(weather).Property(Daily.IsFetched))" />
+ </include>
+ <include content="WeatherWidget" condition="!String.IsEmpty(Weather.Plugin)">
+ <param name="content_include" value="HourlyItems" />
+ <param name="list_id" value="15100" />
+ <param name="widget_header" value="$LOCALIZE[33036]"/>
+ <param name="visible" value="!String.IsEmpty(Window(weather).Property(Hourly.IsFetched))" />
+ </include>
+ </control>
+ <include content="ImageWidget" condition="String.IsEmpty(Weather.plugin)">
+ <param name="text_label" value="$LOCALIZE[31120]" />
+ <param name="button_label" value="$LOCALIZE[31121]" />
+ <param name="button_onclick" value="ActivateWindow(servicesettings,weather)"/>
+ <param name="button_id" value="15300"/>
+ <param name="button2_onclick" value="Skin.SetBool(HomeMenuNoWeatherButton)"/>
+ </include>
+ </control>
+ <control type="group" id="16000">
+ <visible>String.IsEqual(Container(9000).ListItem.Property(id),musicvideos)</visible>
+ <include content="Visible_Right_Delayed">
+ <param name="id" value="musicvideos"/>
+ </include>
+ <control type="grouplist" id="16001">
+ <include>WidgetGroupListCommon</include>
+ <include content="WidgetListCategories" condition="Library.HasContent(musicvideos)">
+ <param name="content_path" value="library://music/musicvideos/"/>
+ <param name="widget_header" value="$LOCALIZE[31148]"/>
+ <param name="widget_target" value="videos"/>
+ <param name="list_id" value="16900"/>
+ </include>
+ <include content="WidgetListEpisodes" condition="Library.HasContent(musicvideos)">
+ <param name="content_path" value="videodb://recentlyaddedmusicvideos/"/>
+ <param name="widget_header" value="$LOCALIZE[20390]"/>
+ <param name="widget_target" value="videos"/>
+ <param name="main_label" value="$INFO[ListItem.Label]" />
+ <param name="sub_label" value="$INFO[ListItem.Artist]" />
+ <param name="thumb_label" value="$INFO[ListItem.Year]" />
+ <param name="fallback_image" value="DefaultMusicSongs.png" />
+ <param name="list_id" value="16300"/>
+ </include>
+ <include content="WidgetListEpisodes" condition="Library.HasContent(musicvideos)">
+ <param name="content_path" value="special://skin/playlists/unwatched_musicvideos.xsp"/>
+ <param name="widget_header" value="$LOCALIZE[31151]"/>
+ <param name="widget_target" value="videos"/>
+ <param name="main_label" value="$INFO[ListItem.Label]" />
+ <param name="sub_label" value="$INFO[ListItem.Artist]" />
+ <param name="thumb_label" value="$INFO[ListItem.Year]" />
+ <param name="fallback_image" value="DefaultMusicSongs.png" />
+ <param name="list_id" value="16400"/>
+ </include>
+ <include content="WidgetListSquare" condition="Library.HasContent(musicvideos)">
+ <param name="content_path" value="special://skin/playlists/random_musicvideo_artists.xsp"/>
+ <param name="widget_header" value="$LOCALIZE[31013]"/>
+ <param name="widget_target" value="music"/>
+ <param name="list_id" value="16200"/>
+ <param name="widget_limit" value="10"/>
+ </include>
+ <include content="WidgetListEpisodes" condition="Library.HasContent(musicvideos)">
+ <param name="content_path" value="special://skin/playlists/random_musicvideos.xsp"/>
+ <param name="widget_header" value="$LOCALIZE[31152]"/>
+ <param name="widget_target" value="videos"/>
+ <param name="main_label" value="$INFO[ListItem.Label]" />
+ <param name="sub_label" value="$INFO[ListItem.Artist]" />
+ <param name="thumb_label" value="$INFO[ListItem.Year]" />
+ <param name="fallback_image" value="DefaultMusicSongs.png" />
+ <param name="list_id" value="16500"/>
+ </include>
+ <include content="WidgetListCategories" condition="Library.HasContent(musicvideos)">
+ <param name="content_path" value="videodb://musicvideos/studios/"/>
+ <param name="widget_header" value="$LOCALIZE[20388]"/>
+ <param name="widget_target" value="music"/>
+ <param name="list_id" value="16600"/>
+ <param name="icon" value="$VAR[WidgetStudioIconVar]"/>
+ <param name="icon_height" value="70"/>
+ </include>
+ </control>
+ <include content="ImageWidget" condition="!Library.HasContent(musicvideos)">
+ <param name="text_label" value="$LOCALIZE[31104]" />
+ <param name="button_label" value="$LOCALIZE[31110]" />
+ <param name="button_onclick" value="ActivateWindow(videos,files,return)"/>
+ <param name="button_id" value="16800"/>
+ <param name="button2_onclick" value="Skin.SetBool(HomeMenuNoMusicVideoButton)"/>
+ </include>
+ </control>
+ <control type="group" id="4000">
+ <visible>String.IsEqual(Container(9000).ListItem.Property(id),pictures)</visible>
+ <include content="Visible_Right_Delayed">
+ <param name="id" value="pictures"/>
+ </include>
+ <control type="grouplist" id="4001">
+ <include>WidgetGroupListCommon</include>
+ <include content="WidgetListCategories" condition="!Skin.HasSetting(HomeMenuNoPicturesButton)">
+ <param name="content_path" value="sources://pictures/"/>
+ <param name="widget_header" value="$LOCALIZE[20094]"/>
+ <param name="widget_target" value="pictures"/>
+ <param name="list_id" value="4100"/>
+ </include>
+ </control>
+ </control>
+ <control type="group" id="21000">
+ <visible>String.IsEqual(Container(9000).ListItem.Property(id),disc)</visible>
+ <include content="Visible_Right_Delayed">
+ <param name="id" value="disc"/>
+ </include>
+ <include content="ImageWidget">
+ <param name="text_label" value="$INFO[System.DVDLabel]" />
+ <param name="button_label" value="$LOCALIZE[341]" />
+ <param name="button_onclick" value="PlayDisc"/>
+ <param name="button_id" value="21100"/>
+ <param name="visible" value="true"/>
+ <param name="button2_label" value="$LOCALIZE[13391]"/>
+ <param name="button2_onclick" value="EjectTray()"/>
+ </include>
+ </control>
+ </control>
+ <control type="group">
+ <depth>DepthContentPanel</depth>
+ <include>OpenClose_Left</include>
+ <include content="ContentPanel">
+ <param name="width" value="522" />
+ </include>
+ <control type="fixedlist" id="9000">
+ <left>0</left>
+ <top>240</top>
+ <width>462</width>
+ <bottom>-10</bottom>
+ <movement>6</movement>
+ <focusposition>1</focusposition>
+ <onfocus>ClearProperty(listposition,home)</onfocus>
+ <onright>SetFocus($INFO[Container(9000).ListItem.Property(menu_id)])</onright>
+ <onup>700</onup>
+ <ondown>700</ondown>
+ <scrolltime tween="cubic" easing="out">500</scrolltime>
+ <focusedlayout height="95">
+ <control type="group">
+ <animation effect="fade" start="100" end="0" time="0">UnFocus</animation>
+ <control type="image">
+ <left>0</left>
+ <top>0</top>
+ <width>462</width>
+ <height>95</height>
+ <texture colordiffuse="button_focus">lists/focus.png</texture>
+ <animation effect="fade" start="100" end="0" time="0" condition="[!Control.HasFocus(9000) + !ControlGroup(700).HasFocus] | System.HasModalDialog">Conditional</animation>
+ </control>
+ <control type="image">
+ <left>-3</left>
+ <top>1</top>
+ <width>95</width>
+ <height>95</height>
+ <texture colordiffuse="button_focus">$INFO[ListItem.Art(thumb)]</texture>
+ <animation effect="fade" start="0" end="100" time="300" reversible="false">Focus</animation>
+ </control>
+ <control type="image">
+ <left>0</left>
+ <top>0</top>
+ <width>95</width>
+ <height>95</height>
+ <texture colordiffuse="51FFFFFF">colors/black.png</texture>
+ <animation effect="fade" start="100" end="0" time="0" condition="[!Control.HasFocus(9000) + !ControlGroup(700).HasFocus] | System.HasModalDialog">Conditional</animation>
+ </control>
+ </control>
+ <control type="image">
+ <left>-3</left>
+ <top>1</top>
+ <width>95</width>
+ <height>95</height>
+ <texture>$INFO[ListItem.Art(thumb)]</texture>
+ </control>
+ <control type="label">
+ <left>104</left>
+ <top>0</top>
+ <height>95</height>
+ <width>560</width>
+ <aligny>center</aligny>
+ <font>font37</font>
+ <label>$INFO[ListItem.Label]</label>
+ <shadowcolor>text_shadow</shadowcolor>
+ </control>
+ </focusedlayout>
+ <itemlayout height="95">
+ <control type="image">
+ <left>-3</left>
+ <top>1</top>
+ <width>95</width>
+ <height>95</height>
+ <texture colordiffuse="44FFFFFF">$INFO[ListItem.Art(thumb)]</texture>
+ </control>
+ <control type="label">
+ <left>104</left>
+ <top>0</top>
+ <height>95</height>
+ <width>560</width>
+ <aligny>center</aligny>
+ <font>font37</font>
+ <label>$INFO[ListItem.Label]</label>
+ <shadowcolor>text_shadow</shadowcolor>
+ </control>
+ </itemlayout>
+ <content>
+ <!-- Start Emby Menu Items -->
+ <item>
+ <label>Emby Movies</label>
+ <onclick condition="String.IsEmpty(Window(Home).Property(first_load_done))">ActivateWindow(Videos,videodb://movies/titles/,return)</onclick>
+ <onclick>ActivateWindow(Videos,plugin://plugin.video.embycon/?mode=SHOW_CONTENT&amp;item_type=Movie&amp;media_type=movies,return)</onclick>
+ <onclick>SetProperty(first_load_done, done, 10000)</onclick>
+ <property name="menu_id">$NUMBER[3000]</property>
+ <thumb>icons/sidemenu/movies.png</thumb>
+ <property name="id">emby_movies</property>
+ </item>
+ <item>
+ <label>Emby TV Shows</label>
+ <onclick condition="String.IsEmpty(Window(Home).Property(first_load_done))">ActivateWindow(Videos,videodb://movies/titles/,return)</onclick>
+ <onclick>ActivateWindow(Videos,plugin://plugin.video.embycon/?mode=SHOW_CONTENT&amp;item_type=Series&amp;media_type=tvshows,return)</onclick>
+ <onclick>SetProperty(first_load_done, done, 10000)</onclick>
+ <property name="menu_id">$NUMBER[4000]</property>
+ <thumb>icons/sidemenu/tv.png</thumb>
+ <property name="id">emby_tvshows</property>
+ </item>
+ <!-- End Emby Menu Items -->
+ <item>
+ <label>$LOCALIZE[342]</label>
+ <onclick condition="Library.HasContent(movies)">ActivateWindow(Videos,videodb://movies/titles/,return)</onclick>
+ <onclick condition="!Library.HasContent(movies)">ActivateWindow(Videos,sources://video/,return)</onclick>
+ <property name="menu_id">$NUMBER[5000]</property>
+ <thumb>icons/sidemenu/movies.png</thumb>
+ <property name="id">movies</property>
+ <visible>!Skin.HasSetting(HomeMenuNoMovieButton)</visible>
+ </item>
+ <item>
+ <label>$LOCALIZE[20343]</label>
+ <onclick condition="Library.HasContent(tvshows)">ActivateWindow(Videos,videodb://tvshows/titles/,return)</onclick>
+ <onclick condition="!Library.HasContent(tvshows)">ActivateWindow(Videos,sources://video/,return)</onclick>
+ <property name="menu_id">$NUMBER[6000]</property>
+ <thumb>icons/sidemenu/tv.png</thumb>
+ <property name="id">tvshows</property>
+ <visible>!Skin.HasSetting(HomeMenuNoTVShowButton)</visible>
+ </item>
+ <item>
+ <label>$LOCALIZE[2]</label>
+ <onclick>ActivateWindow(Music,root,return)</onclick>
+ <property name="menu_id">$NUMBER[7000]</property>
+ <thumb>icons/sidemenu/music.png</thumb>
+ <property name="id">music</property>
+ <visible>!Skin.HasSetting(HomeMenuNoMusicButton)</visible>
+ </item>
+ <item>
+ <label>$LOCALIZE[427]</label>
+ <onclick>PlayDisc</onclick>
+ <property name="menu_id">$NUMBER[21000]</property>
+ <thumb>icons/sidemenu/disc.png</thumb>
+ <property name="id">disc</property>
+ <visible>System.HasMediaDVD</visible>
+ </item>
+ <item>
+ <label>$LOCALIZE[20389]</label>
+ <property name="menu_id">$NUMBER[16000]</property>
+ <onclick>ActivateWindow(Videos,musicvideos,return)</onclick>
+ <thumb>icons/sidemenu/musicvideos.png</thumb>
+ <property name="id">musicvideos</property>
+ <visible>!Skin.HasSetting(HomeMenuNoMusicVideoButton)</visible>
+ </item>
+ <item>
+ <label>$LOCALIZE[19020]</label>
+ <property name="menu_id">$NUMBER[12000]</property>
+ <onclick>ActivateWindow(TVChannels)</onclick>
+ <thumb>icons/sidemenu/livetv.png</thumb>
+ <property name="id">livetv</property>
+ <visible>!Skin.HasSetting(HomeMenuNoTVButton)</visible>
+ </item>
+ <item>
+ <label>$LOCALIZE[19021]</label>
+ <property name="menu_id">$NUMBER[13000]</property>
+ <onclick>ActivateWindow(RadioChannels)</onclick>
+ <thumb>icons/sidemenu/radio.png</thumb>
+ <property name="id">radio</property>
+ <visible>!Skin.HasSetting(HomeMenuNoRadioButton)</visible>
+ </item>
+ <item>
+ <label>$LOCALIZE[24001]</label>
+ <property name="menu_id">$NUMBER[8000]</property>
+ <onclick>ActivateWindow(1100)</onclick>
+ <thumb>icons/sidemenu/addons.png</thumb>
+ <property name="id">addons</property>
+ <visible>!Skin.HasSetting(HomeMenuNoProgramsButton)</visible>
+ </item>
+ <item>
+ <label>$LOCALIZE[1]</label>
+ <onclick>ActivateWindow(Pictures)</onclick>
+ <property name="menu_id">$NUMBER[4000]</property>
+ <thumb>icons/sidemenu/pictures.png</thumb>
+ <property name="id">pictures</property>
+ <visible>!Skin.HasSetting(HomeMenuNoPicturesButton)</visible>
+ </item>
+ <item>
+ <label>$LOCALIZE[3]</label>
+ <onclick>ActivateWindow(Videos,root)</onclick>
+ <property name="menu_id">$NUMBER[11000]</property>
+ <thumb>icons/sidemenu/videos.png</thumb>
+ <property name="id">video</property>
+ <visible>!Skin.HasSetting(HomeMenuNoVideosButton)</visible>
+ </item>
+ <item>
+ <label>$LOCALIZE[10134]</label>
+ <onclick>ActivateWindow(favourites)</onclick>
+ <property name="menu_id">$NUMBER[14000]</property>
+ <thumb>icons/sidemenu/favourites.png</thumb>
+ <property name="id">favorites</property>
+ <visible>!Skin.HasSetting(HomeMenuNoFavButton)</visible>
+ </item>
+ <item>
+ <label>$LOCALIZE[8]</label>
+ <onclick condition="!String.IsEmpty(Weather.Plugin)">ActivateWindow(Weather)</onclick>
+ <onclick condition="String.IsEmpty(Weather.Plugin)">ReplaceWindow(servicesettings,weather)</onclick>
+ <property name="menu_id">$NUMBER[15000]</property>
+ <thumb>icons/sidemenu/weather.png</thumb>
+ <property name="id">weather</property>
+ <visible>!Skin.HasSetting(HomeMenuNoWeatherButton)</visible>
+ </item>
+ </content>
+ </control>
+ <control type="grouplist" id="700">
+ <orientation>horizontal</orientation>
+ <itemgap>0</itemgap>
+ <left>-8</left>
+ <width>480</width>
+ <height>110</height>
+ <top>100</top>
+ <onup>SetFocus(9000)</onup>
+ <onup>PageDown</onup>
+ <onup>PageDown</onup>
+ <ondown>SetFocus(9000)</ondown>
+ <ondown>PageUp</ondown>
+ <ondown>PageUp</ondown>
+ <onright>2000</onright>
+ <align>justify</align>
+ <include content="IconButton">
+ <param name="control_id" value="804" />
+ <param name="onclick" value="ActivateWindow(shutdownmenu)" />
+ <param name="icon" value="icons/power.png" />
+ <param name="label" value="$LOCALIZE[33060]" />
+ </include>
+ <include content="IconButton">
+ <param name="control_id" value="802" />
+ <param name="onclick" value="ActivateWindow(settings)" />
+ <param name="icon" value="icons/settings.png" />
+ <param name="label" value="$LOCALIZE[21417]" />
+ </include>
+ <include content="IconButton">
+ <param name="control_id" value="801" />
+ <param name="onclick" value="ActivateWindow(1107)" />
+ <param name="icon" value="icons/search.png" />
+ <param name="label" value="$LOCALIZE[137]" />
+ </include>
+ <include content="IconButton">
+ <param name="control_id" value="803" />
+ <param name="onclick" value="Fullscreen" />
+ <param name="icon" value="icons/now-playing/fullscreen.png" />
+ <param name="label" value="$LOCALIZE[31000]" />
+ <param name="visible" value="Player.HasMedia" />
+ </include>
+ </control>
+ </control>
+ <include>BottomBar</include>
+ <include content="TopBar">
+ <param name="breadcrumbs_label" value="" />
+ </include>
+ <control type="group">
+ <depth>DepthBars</depth>
+ <animation effect="slide" end="0,-90" time="300" tween="sine" easing="inout" condition="$EXP[infodialog_active]">conditional</animation>
+ <animation effect="fade" start="0" end="100" time="300">WindowOpen</animation>
+ <animation effect="fade" start="100" end="0" time="200">WindowClose</animation>
+ <top>30</top>
+ <left>90</left>
+ <control type="image">
+ <aspectratio>keep</aspectratio>
+ <width>56</width>
+ <height>56</height>
+ <texture colordiffuse="button_focus">icons/logo.png</texture>
+ </control>
+ <control type="image">
+ <left>40</left>
+ <top>10</top>
+ <aspectratio>keep</aspectratio>
+ <width>192</width>
+ <height>36</height>
+ <texture>icons/logo-text.png</texture>
+ </control>
+ </control>
+ <control type="rss">
+ <animation effect="slide" end="0,90" time="300" tween="sine" easing="inout" condition="$EXP[infodialog_active]">conditional</animation>
+ <animation effect="fade" start="0" end="100" time="400">WindowOpen</animation>
+ <animation effect="fade" start="100" end="0" time="300">WindowClose</animation>
+ <left>0</left>
+ <bottom>0</bottom>
+ <height>39</height>
+ <width>100%</width>
+ <font>font12</font>
+ <urlset>1</urlset>
+ <hitrect x="-100" y="0" w="1" h="1" />
+ <titlecolor>button_focus</titlecolor>
+ <textcolor>button_focus</textcolor>
+ <shadowcolor>text_shadow</shadowcolor>
+ <headlinecolor>FFC0C0C0</headlinecolor>
+ </control>
+ </control>
+ </controls>
+</window>
diff --git a/plugin.video.embycon/resources/skins/skin.estuary/xml/Home-17.3.xml b/plugin.video.embycon/resources/skins/skin.estuary/xml/Home-17.3.xml
index f12f5c5..8c73c20 100644
--- a/plugin.video.embycon/resources/skins/skin.estuary/xml/Home-17.3.xml
+++ b/plugin.video.embycon/resources/skins/skin.estuary/xml/Home-17.3.xml
@@ -52,19 +52,19 @@
<control type="grouplist" id="3001">
<include>WidgetGroupListCommon</include>
<include content="WidgetListPoster" condition="true">
- <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&type=recent_movies"/>
+ <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&amp;type=recent_movies&amp;reload=$INFO[Window(Home).Property(plugin.video.embycon-embycon_widget_reload)]"/>
<param name="widget_header" value="Recently Added"/>
<param name="widget_target" value="videos"/>
<param name="list_id" value="3800"/>
</include>
<include content="WidgetListPoster" condition="true">
- <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&type=inprogress_movies"/>
+ <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&amp;type=inprogress_movies&amp;reload=$INFO[Window(Home).Property(plugin.video.embycon-embycon_widget_reload)]"/>
<param name="widget_header" value="In Progress"/>
<param name="widget_target" value="videos"/>
<param name="list_id" value="3900"/>
</include>
<include content="WidgetListPoster" condition="true">
- <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&type=random_movies"/>
+ <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&amp;type=random_movies&amp;reload=$INFO[Window(Home).Property(plugin.video.embycon-embycon_widget_reload)]"/>
<param name="widget_header" value="Random"/>
<param name="widget_target" value="videos"/>
<param name="list_id" value="3100"/>
@@ -79,19 +79,19 @@
<control type="grouplist" id="4001">
<include>WidgetGroupListCommon</include>
<include content="WidgetListEpisodes" condition="true">
- <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&type=recent_episodes"/>
+ <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&amp;type=recent_episodes&amp;reload=$INFO[Window(Home).Property(plugin.video.embycon-embycon_widget_reload)]"/>
<param name="widget_header" value="Recently Added"/>
<param name="widget_target" value="videos"/>
<param name="list_id" value="4900"/>
</include>
<include content="WidgetListEpisodes" condition="true">
- <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&type=inprogress_episodes"/>
+ <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&amp;type=inprogress_episodes&amp;reload=$INFO[Window(Home).Property(plugin.video.embycon-embycon_widget_reload)]"/>
<param name="widget_header" value="In Progress"/>
<param name="widget_target" value="videos"/>
<param name="list_id" value="4100"/>
</include>
<include content="WidgetListEpisodes" condition="true">
- <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&type=nextup_episodes"/>
+ <param name="content_path" value="plugin://plugin.video.embycon?mode=WIDGET_CONTENT&amp;type=nextup_episodes&amp;reload=$INFO[Window(Home).Property(plugin.video.embycon-embycon_widget_reload)]"/>
<param name="widget_header" value="Next Up"/>
<param name="widget_target" value="videos"/>
<param name="list_id" value="4200"/>
@@ -856,14 +856,16 @@
<!-- Start Emby Menu Items -->
<item>
<label>Emby Movies</label>
- <onclick>RunAddon(plugin.video.embycon, /?mode=SHOW_CONTENT&amp;item_type=Movie&amp;media_type=movies)</onclick>
+ <onclick>ActivateWindow(Videos,plugin://plugin.video.embycon/?mode=SHOW_CONTENT&amp;item_type=Movie&amp;media_type=movies,return)</onclick>
+ <!--<onclick>RunAddon(plugin.video.embycon, /?mode=SHOW_CONTENT&amp;item_type=Movie&amp;media_type=movies)</onclick>-->
<property name="menu_id">$NUMBER[3000]</property>
<thumb>icons/sidemenu/movies.png</thumb>
<property name="id">emby_movies</property>
</item>
<item>
<label>Emby TV Shows</label>
- <onclick>RunAddon(plugin.video.embycon, /?mode=SHOW_CONTENT&amp;item_type=Series&amp;media_type=tvshows)</onclick>
+ <onclick>ActivateWindow(Videos,plugin://plugin.video.embycon/?mode=SHOW_CONTENT&amp;item_type=Series&amp;media_type=tvshows,return)</onclick>
+ <!--<onclick>RunAddon(plugin.video.embycon, /?mode=SHOW_CONTENT&amp;item_type=Series&amp;media_type=tvshows)</onclick>-->
<property name="menu_id">$NUMBER[4000]</property>
<thumb>icons/sidemenu/tv.png</thumb>
<property name="id">emby_tvshows</property>
diff --git a/plugin.video.embycon/service.py b/plugin.video.embycon/service.py
index 2a71d93..0502978 100644
--- a/plugin.video.embycon/service.py
+++ b/plugin.video.embycon/service.py
@@ -6,12 +6,14 @@ import xbmcaddon
import xbmcgui
import time
import json
+import traceback
from resources.lib.downloadutils import DownloadUtils
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.widgets import checkForNewContent
# clear user and token when logging in
home_window = HomeWindow()
@@ -77,6 +79,7 @@ def promptForStopActions(item_id, current_possition):
settings = xbmcaddon.Addon(id='plugin.video.embycon')
prompt_next_percentage = int(settings.getSetting('promptPlayNextEpisodePercentage'))
+ play_prompt = settings.getSetting('promptPlayNextEpisodePercentage_prompt') == "true"
prompt_delete_episode_percentage = int(settings.getSetting('promptDeleteEpisodePercentage'))
prompt_delete_movie_percentage = int(settings.getSetting('promptDeleteMoviePercentage'))
@@ -151,8 +154,14 @@ def promptForStopActions(item_id, current_possition):
item_list = items_result.get("Items", [])
for item in item_list:
index = item.get("IndexNumber", -1)
- if index > item_index: # find the next episode in the season
- resp = xbmcgui.Dialog().yesno(i18n("play_next_title"), i18n("play_next_question"), autoclose=10000)
+ if index == item_index + 1: # find the very next episode in the season
+
+ resp = True
+ if play_prompt:
+ #next_epp_name = str(index) + " of " + str(item_list[-1].get("IndexNumber", -1)) + " - " + item.get("Name", "n/a")
+ next_epp_name = ("%02d - " % (index,)) + item.get("Name", "n/a")
+ resp = xbmcgui.Dialog().yesno(i18n("play_next_title"), i18n("play_next_question"), next_epp_name, autoclose=10000)
+
if resp:
next_item_id = item.get("Id")
log.debug("Playing Next Episode: %s" % next_item_id)
@@ -287,9 +296,10 @@ class Service(xbmc.Player):
monitor = Service()
-last_progress_update = time.time()
-download_utils.checkVersion()
home_window = HomeWindow()
+last_progress_update = time.time()
+last_content_check = time.time()
+last_version_check = 0
# monitor.abortRequested() is causes issues, it currently triggers for all addon cancelations which causes
# the service to exit when a user cancels an addon load action. This is a bug in Kodi.
@@ -297,28 +307,37 @@ home_window = HomeWindow()
while not xbmc.abortRequested:
- if xbmc.Player().isPlaying():
-
- try:
+ try:
+ if xbmc.Player().isPlaying():
+ # if playing every 10 seconds updated the server with progress
if (time.time() - last_progress_update) > 10:
last_progress_update = time.time()
sendProgress()
+ else:
+ # if we have a play item them trigger playback
+ 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)
+
+ # if not playing every 60 seonds check for new widget content
+ if (time.time() - last_content_check) > 60:
+ last_content_check = time.time()
+ checkForNewContent()
+
+ # check version
+ if (time.time() - last_version_check) > (60 * 60 * 6): # every 6 hours
+ last_version_check = time.time()
+ download_utils.checkVersion()
+
+ except Exception as error:
+ log.error("Exception in Playback Monitor : " + str(error))
+ log.error(traceback.format_exc())
- 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)
-
- home_window.setProperty("Service_Timestamp", str(int(time.time())))
xbmc.sleep(1000)
# clear user and token when loggin off
-home_window.clearProperty("Service_Timestamp")
home_window.clearProperty("userid")
home_window.clearProperty("AccessToken")
home_window.clearProperty("Params")