Merge pull request #263 from mcarlton00/pep8-refactor
pep8 refactor - part 1
This commit is contained in:
@@ -13,12 +13,12 @@ import xbmcgui
|
||||
import xbmcaddon
|
||||
import xbmc
|
||||
from six import StringIO
|
||||
from six.moves.urllib.parse import quote, unquote, parse_qsl
|
||||
from six.moves.urllib.parse import quote, unquote, parse_qsl, urlencode
|
||||
|
||||
from .jellyfin import api
|
||||
from .utils import (
|
||||
translate_string, get_version, load_user_details, get_art_url,
|
||||
get_default_filters, translate_path, kodi_version
|
||||
get_default_filters, translate_path, kodi_version, get_jellyfin_url
|
||||
)
|
||||
from .kodi_utils import HomeWindow
|
||||
from .datamanager import clear_cached_server_data
|
||||
@@ -45,6 +45,7 @@ __addon__ = xbmcaddon.Addon()
|
||||
__addondir__ = translate_path(__addon__.getAddonInfo('profile'))
|
||||
__cwd__ = __addon__.getAddonInfo('path')
|
||||
PLUGINPATH = translate_path(os.path.join(__cwd__))
|
||||
addon_id = __addon__.getAddonInfo('id')
|
||||
|
||||
log = LazyLogger(__name__)
|
||||
|
||||
@@ -66,7 +67,9 @@ def main_entry_point():
|
||||
|
||||
log.debug("Running Python: {0}".format(sys.version_info))
|
||||
log.debug("Running JellyCon: {0}".format(get_version()))
|
||||
log.debug("Kodi BuildVersion: {0}".format(xbmc.getInfoLabel("System.BuildVersion")))
|
||||
log.debug("Kodi BuildVersion: {0}".format(
|
||||
xbmc.getInfoLabel("System.BuildVersion"))
|
||||
)
|
||||
log.debug("Kodi Version: {0}".format(kodi_version()))
|
||||
log.debug("Script argument data: {0}".format(sys.argv))
|
||||
|
||||
@@ -78,7 +81,9 @@ def main_entry_point():
|
||||
|
||||
mode = params.get("mode", None)
|
||||
|
||||
if len(params) == 1 and request_path and request_path.find("/library/movies") > -1:
|
||||
if (len(params) == 1 and request_path
|
||||
and request_path.find("/library/movies") > -1):
|
||||
|
||||
check_server()
|
||||
new_params = {}
|
||||
new_params["item_type"] = "Movie"
|
||||
@@ -117,7 +122,9 @@ def main_entry_point():
|
||||
__addon__.openSettings()
|
||||
window = xbmcgui.getCurrentWindowId()
|
||||
if window == 10000:
|
||||
log.debug("Currently in home - refreshing to allow new settings to be taken")
|
||||
log.debug(
|
||||
"Currently in home - refresh to allow new settings to be taken"
|
||||
)
|
||||
xbmc.executebuiltin("ActivateWindow(Home)")
|
||||
elif mode == "CLEAR_CACHE":
|
||||
clear_cached_server_data()
|
||||
@@ -139,13 +146,6 @@ def main_entry_point():
|
||||
show_server_sessions()
|
||||
elif mode == "SHOW_ADDON_MENU":
|
||||
display_menu(params)
|
||||
elif mode == "GET_CONTENT_BY_TV_SHOW":
|
||||
parent_id = __get_parent_id_from(params)
|
||||
if parent_id is not None:
|
||||
enriched_url = param_url + "&ParentId=" + parent_id
|
||||
get_content(enriched_url, params)
|
||||
else:
|
||||
log.info("Unable to find TV show parent ID.")
|
||||
else:
|
||||
log.debug("JellyCon -> Mode: {0}".format(mode))
|
||||
log.debug("JellyCon -> URL: {0}".format(param_url))
|
||||
@@ -162,7 +162,9 @@ def main_entry_point():
|
||||
pr.disable()
|
||||
|
||||
file_time_stamp = time.strftime("%Y%m%d-%H%M%S")
|
||||
tab_file_name = __addondir__ + "profile(" + file_time_stamp + ").txt"
|
||||
tab_file_name = "{}-profile({}).txt".format(
|
||||
__addondir__, file_time_stamp
|
||||
)
|
||||
s = StringIO()
|
||||
ps = pstats.Stats(pr, stream=s)
|
||||
ps = ps.sort_stats('cumulative')
|
||||
@@ -176,33 +178,6 @@ def main_entry_point():
|
||||
log.debug("===== JellyCon FINISHED =====")
|
||||
|
||||
|
||||
def __enrich_url(param_url, params):
|
||||
enriched_url = param_url
|
||||
parent_id = __get_parent_id_from(params)
|
||||
if parent_id is not None:
|
||||
enriched_url = param_url + "&ParentId=" + parent_id
|
||||
return enriched_url
|
||||
|
||||
|
||||
def __get_parent_id_from(params):
|
||||
result = None
|
||||
show_provider_ids = params.get("show_ids")
|
||||
if show_provider_ids is not None:
|
||||
log.debug("TV show providers IDs: {}".format(show_provider_ids))
|
||||
get_show_url = "/Users/{}/Items?fields=MediaStreams&Recursive=true" \
|
||||
"&IncludeItemTypes=series&IncludeMedia=true&ImageTypeLimit=1&Limit=16" \
|
||||
"&AnyProviderIdEquals={}".format(api.user_id, show_provider_ids)
|
||||
content = api.get(get_show_url)
|
||||
show = content.get("Items")
|
||||
if len(show) == 1:
|
||||
result = content.get("Items")[0].get("Id")
|
||||
else:
|
||||
log.debug("TV show not found for ids: {}".format(show_provider_ids))
|
||||
else:
|
||||
log.error("TV show parameter not found in request.")
|
||||
return result
|
||||
|
||||
|
||||
def toggle_watched(params):
|
||||
log.debug("toggle_watched: {0}".format(params))
|
||||
item_id = params.get("item_id", None)
|
||||
@@ -224,61 +199,61 @@ def toggle_watched(params):
|
||||
|
||||
def mark_item_watched(item_id):
|
||||
log.debug("Mark Item Watched: {0}".format(item_id))
|
||||
url = "/Users/{}/PlayedItems/{}".format(user_details.get('user_id'), item_id)
|
||||
url = "/Users/{}/PlayedItems/{}".format(api.user_id, item_id)
|
||||
api.post(url)
|
||||
check_for_new_content()
|
||||
home_window = HomeWindow()
|
||||
last_url = home_window.get_property("last_content_url")
|
||||
if last_url:
|
||||
log.debug("markWatched_lastUrl: {0}".format(last_url))
|
||||
home_window.set_property("skip_cache_for_" + last_url, "true")
|
||||
home_window.set_property("skip_cache_for_{}".format(last_url), "true")
|
||||
|
||||
xbmc.executebuiltin("Container.Refresh")
|
||||
|
||||
|
||||
def mark_item_unwatched(item_id):
|
||||
log.debug("Mark Item UnWatched: {0}".format(item_id))
|
||||
url = "/Users/{}/PlayedItems/{}".format(user_details.get('user_id'), item_id)
|
||||
url = "/Users/{}/PlayedItems/{}".format(api.user_id, item_id)
|
||||
api.delete(url)
|
||||
check_for_new_content()
|
||||
home_window = HomeWindow()
|
||||
last_url = home_window.get_property("last_content_url")
|
||||
if last_url:
|
||||
log.debug("markUnwatched_lastUrl: {0}".format(last_url))
|
||||
home_window.set_property("skip_cache_for_" + last_url, "true")
|
||||
home_window.set_property("skip_cache_for_{}".format(last_url), "true")
|
||||
|
||||
xbmc.executebuiltin("Container.Refresh")
|
||||
|
||||
|
||||
def mark_item_favorite(item_id):
|
||||
log.debug("Add item to favourites: {0}".format(item_id))
|
||||
url = "/Users/{}/FavoriteItems/{}".format(user_details.get('user_id'), item_id)
|
||||
url = "/Users/{}/FavoriteItems/{}".format(api.user_id, item_id)
|
||||
api.post(url)
|
||||
check_for_new_content()
|
||||
home_window = HomeWindow()
|
||||
last_url = home_window.get_property("last_content_url")
|
||||
if last_url:
|
||||
home_window.set_property("skip_cache_for_" + last_url, "true")
|
||||
home_window.set_property("skip_cache_for_{}".format(last_url), "true")
|
||||
|
||||
xbmc.executebuiltin("Container.Refresh")
|
||||
|
||||
|
||||
def unmark_item_favorite(item_id):
|
||||
log.debug("Remove item from favourites: {0}".format(item_id))
|
||||
url = "/Users/{}/FavoriteItems/{}".format(user_details.get('user_id'), item_id)
|
||||
url = "/Users/{}/FavoriteItems/{}".format(api.user_id, item_id)
|
||||
api.delete(url)
|
||||
check_for_new_content()
|
||||
home_window = HomeWindow()
|
||||
last_url = home_window.get_property("last_content_url")
|
||||
if last_url:
|
||||
home_window.set_property("skip_cache_for_" + last_url, "true")
|
||||
home_window.set_property("skip_cache_for_{}".format(last_url), "true")
|
||||
|
||||
xbmc.executebuiltin("Container.Refresh")
|
||||
|
||||
|
||||
def delete(item_id):
|
||||
|
||||
item = api.delete("/Users/{}/Items/{}".format(user_details.get('user_id'), item_id))
|
||||
item = api.delete("/Users/{}/Items/{}".format(api.user_id, item_id))
|
||||
|
||||
item_id = item.get("Id")
|
||||
item_name = item.get("Name", "")
|
||||
@@ -288,18 +263,24 @@ def delete(item_id):
|
||||
final_name = ""
|
||||
|
||||
if series_name:
|
||||
final_name += series_name + " - "
|
||||
final_name += "{} -".format(series_name)
|
||||
|
||||
if ep_number != -1:
|
||||
final_name += "Episode %02d - " % (ep_number,)
|
||||
final_name += "Episode {:02d} - ".format(ep_number)
|
||||
|
||||
final_name += item_name
|
||||
|
||||
if not item.get("CanDelete", False):
|
||||
xbmcgui.Dialog().ok(translate_string(30135), translate_string(30417), final_name)
|
||||
xbmcgui.Dialog().ok(
|
||||
translate_string(30135), translate_string(30417), final_name
|
||||
)
|
||||
return
|
||||
|
||||
return_value = xbmcgui.Dialog().yesno(translate_string(30091), '{}\n{}'.format(final_name, translate_string(30092)))
|
||||
return_value = xbmcgui.Dialog().yesno(
|
||||
translate_string(30091), '{}\n{}'.format(
|
||||
final_name, translate_string(30092)
|
||||
)
|
||||
)
|
||||
if return_value:
|
||||
log.debug('Deleting Item: {0}'.format(item_id))
|
||||
url = '/Items/{}'.format(item_id)
|
||||
@@ -311,7 +292,9 @@ def delete(item_id):
|
||||
home_window = HomeWindow()
|
||||
last_url = home_window.get_property("last_content_url")
|
||||
if last_url:
|
||||
home_window.set_property("skip_cache_for_" + last_url, "true")
|
||||
home_window.set_property(
|
||||
"skip_cache_for_{}".format(last_url), "true"
|
||||
)
|
||||
|
||||
xbmc.executebuiltin("Container.Refresh")
|
||||
|
||||
@@ -330,7 +313,7 @@ def get_params():
|
||||
param = dict(parse_qsl(paramstring[1:]))
|
||||
|
||||
# add plugin path
|
||||
request_path = plugin_path.replace("plugin://plugin.video.jellycon", "")
|
||||
request_path = plugin_path.replace("plugin://{}".format(addon_id), "")
|
||||
param["request_path"] = request_path
|
||||
|
||||
log.debug("JellyCon -> Detected parameters: {0}".format(param))
|
||||
@@ -354,7 +337,8 @@ def show_menu(params):
|
||||
action_items = []
|
||||
|
||||
# Additional items to include in the context menu for different item types
|
||||
if result["Type"] in ["Episode", "Movie", "Music", "Video", "Audio", "TvChannel", "Program", "MusicVideo"]:
|
||||
if result["Type"] in ["Episode", "Movie", "Music", "Video", "Audio",
|
||||
"TvChannel", "Program", "MusicVideo"]:
|
||||
li = xbmcgui.ListItem(translate_string(30314), offscreen=True)
|
||||
li.setProperty('menu_id', 'play')
|
||||
action_items.append(li)
|
||||
@@ -364,7 +348,8 @@ def show_menu(params):
|
||||
li.setProperty('menu_id', 'play_all')
|
||||
action_items.append(li)
|
||||
|
||||
if result["Type"] in ["MusicArtist", "MusicAlbum", "Playlist", "Series", "Season"]:
|
||||
if result["Type"] in ["MusicArtist", "MusicAlbum", "Playlist",
|
||||
"Series", "Season"]:
|
||||
li = xbmcgui.ListItem(translate_string(30448), offscreen=True)
|
||||
li.setProperty('menu_id', 'shuffle')
|
||||
action_items.append(li)
|
||||
@@ -374,12 +359,14 @@ def show_menu(params):
|
||||
li.setProperty('menu_id', 'instant_mix')
|
||||
action_items.append(li)
|
||||
|
||||
if result["Type"] in ["Episode", "Movie", "Video", "TvChannel", "Program", "MusicVideo"]:
|
||||
if result["Type"] in ["Episode", "Movie", "Video", "TvChannel",
|
||||
"Program", "MusicVideo"]:
|
||||
li = xbmcgui.ListItem(translate_string(30275), offscreen=True)
|
||||
li.setProperty('menu_id', 'transcode')
|
||||
action_items.append(li)
|
||||
|
||||
if result["Type"] in ["Episode", "Movie", "Music", "Video", "Audio", "MusicArtist", "MusicAlbum", "MusicVideo"]:
|
||||
if result["Type"] in ["Episode", "Movie", "Music", "Video", "Audio",
|
||||
"MusicArtist", "MusicAlbum", "MusicVideo"]:
|
||||
li = xbmcgui.ListItem(translate_string(30402), offscreen=True)
|
||||
li.setProperty('menu_id', 'add_to_playlist')
|
||||
action_items.append(li)
|
||||
@@ -452,12 +439,15 @@ def show_menu(params):
|
||||
window = xbmcgui.Window(xbmcgui.getCurrentWindowId())
|
||||
container_view_id = str(window.getFocusId())
|
||||
container_content_type = xbmc.getInfoLabel("Container.Content")
|
||||
view_key = "view-" + container_content_type
|
||||
view_key = "view-{}".format(container_content_type)
|
||||
current_default_view = settings.getSetting(view_key)
|
||||
view_match = container_view_id == current_default_view
|
||||
log.debug("View ID:{0} Content type:{1}".format(container_view_id, container_content_type))
|
||||
log.debug("View ID:{0} Content type:{1}".format(
|
||||
container_view_id, container_content_type)
|
||||
)
|
||||
|
||||
if container_content_type in ["movies", "tvshows", "seasons", "episodes", "sets"]:
|
||||
if container_content_type in ["movies", "tvshows", "seasons",
|
||||
"episodes", "sets"]:
|
||||
if view_match:
|
||||
li = xbmcgui.ListItem("Unset as default view", offscreen=True)
|
||||
li.setProperty('menu_id', 'unset_view')
|
||||
@@ -482,20 +472,28 @@ def show_menu(params):
|
||||
play_action(params)
|
||||
|
||||
elif selected_action == "set_view":
|
||||
log.debug("Settign view type for {0} to {1}".format(view_key, container_view_id))
|
||||
log.debug("Settign view type for {0} to {1}".format(
|
||||
view_key, container_view_id)
|
||||
)
|
||||
settings.setSetting(view_key, container_view_id)
|
||||
|
||||
elif selected_action == "unset_view":
|
||||
log.debug("Un-Settign view type for {0} to {1}".format(view_key, container_view_id))
|
||||
log.debug("Un-Settign view type for {0} to {1}".format(
|
||||
view_key, container_view_id)
|
||||
)
|
||||
settings.setSetting(view_key, "")
|
||||
|
||||
elif selected_action == "refresh_server":
|
||||
url = ("/Items/" + item_id + "/Refresh" +
|
||||
"?Recursive=true" +
|
||||
"&ImageRefreshMode=FullRefresh" +
|
||||
"&MetadataRefreshMode=FullRefresh" +
|
||||
"&ReplaceAllImages=true" +
|
||||
"&ReplaceAllMetadata=true")
|
||||
url_path = "/Items/{}/Refresh".format(item_id)
|
||||
url_params = {
|
||||
"Recursive": True,
|
||||
"ImageRefreshMode": "FullRefresh",
|
||||
"MetadataRefreshMode": "FullRefresh",
|
||||
"ReplaceAllImages": True,
|
||||
"ReplaceAllMetadata": True
|
||||
}
|
||||
|
||||
url = get_jellyfin_url(url_path, url_params)
|
||||
res = api.post(url)
|
||||
log.debug("Refresh Server Responce: {0}".format(res))
|
||||
|
||||
@@ -513,7 +511,9 @@ def show_menu(params):
|
||||
last_url = home_window.get_property("last_content_url")
|
||||
if last_url:
|
||||
log.debug("markUnwatched_lastUrl: {0}".format(last_url))
|
||||
home_window.set_property("skip_cache_for_" + last_url, "true")
|
||||
home_window.set_property(
|
||||
"skip_cache_for_{}".format(last_url), "true"
|
||||
)
|
||||
|
||||
xbmc.executebuiltin("Container.Refresh")
|
||||
|
||||
@@ -534,17 +534,22 @@ def show_menu(params):
|
||||
elif selected_action == "transcode":
|
||||
params['force_transcode'] = 'true'
|
||||
|
||||
force_max_stream_bitrate = settings.getSetting("force_max_stream_bitrate")
|
||||
initial_bitrate_value = int(force_max_stream_bitrate)
|
||||
bitrate_dialog = BitrateDialog("BitrateDialog.xml", PLUGINPATH, "default", "720p")
|
||||
max_bitrate = settings.getSetting("force_max_stream_bitrate")
|
||||
initial_bitrate_value = int(max_bitrate)
|
||||
bitrate_dialog = BitrateDialog(
|
||||
"BitrateDialog.xml", PLUGINPATH, "default", "720p"
|
||||
)
|
||||
bitrate_dialog.initial_bitrate_value = initial_bitrate_value
|
||||
bitrate_dialog.doModal()
|
||||
selected_transcode_value = bitrate_dialog.selected_transcode_value
|
||||
del bitrate_dialog
|
||||
log.debug("selected_transcode_value: {0}".format(selected_transcode_value))
|
||||
log.debug("selected_transcode_value: {0}".format(
|
||||
selected_transcode_value)
|
||||
)
|
||||
|
||||
if selected_transcode_value > 0:
|
||||
settings.setSetting("force_max_stream_bitrate", str(selected_transcode_value))
|
||||
settings.setSetting(
|
||||
"force_max_stream_bitrate", str(selected_transcode_value))
|
||||
|
||||
play_action(params)
|
||||
|
||||
@@ -568,25 +573,49 @@ def show_menu(params):
|
||||
delete(item_id)
|
||||
|
||||
elif selected_action == "show_extras":
|
||||
u = "/Users/{}/Items/{}/SpecialFeatures".format(api.user_id, item_id)
|
||||
action_url = ("plugin://plugin.video.jellycon/?url=" + quote(u) + "&mode=GET_CONTENT&media_type=Videos")
|
||||
built_in_command = 'ActivateWindow(Videos, ' + action_url + ', return)'
|
||||
url = "/Users/{}/Items/{}/SpecialFeatures".format(api.user_id, item_id)
|
||||
plugin_params = {
|
||||
"url": url,
|
||||
"mode": "GET_CONTENT",
|
||||
"media_type": "Videos"
|
||||
}
|
||||
|
||||
action_params = urlencode(plugin_params)
|
||||
|
||||
action_url = "plugin://{}/?{}".format(addon_id, action_params)
|
||||
built_in_command = 'ActivateWindow(Videos, {}, return)'.format(
|
||||
action_url
|
||||
)
|
||||
xbmc.executebuiltin(built_in_command)
|
||||
|
||||
elif selected_action == "view_season":
|
||||
xbmc.executebuiltin("Dialog.Close(all,true)")
|
||||
parent_id = result["ParentId"]
|
||||
series_id = result["SeriesId"]
|
||||
u = ('/Shows/' + series_id +
|
||||
'/Episodes'
|
||||
'?userId={}'.format(api.user_id) +
|
||||
'&seasonId=' + parent_id +
|
||||
'&IsVirtualUnAired=false' +
|
||||
'&IsMissing=false' +
|
||||
'&Fields=SpecialEpisodeNumbers,{}'.format(get_default_filters()) +
|
||||
'&format=json')
|
||||
action_url = ("plugin://plugin.video.jellycon/?url=" + quote(u) + "&mode=GET_CONTENT&media_type=Season")
|
||||
built_in_command = 'ActivateWindow(Videos, ' + action_url + ', return)'
|
||||
|
||||
url_path = "/Shows/{}/Episodes".format(series_id)
|
||||
url_params = {
|
||||
"userId": api.user_id,
|
||||
"seasonId": parent_id,
|
||||
"IsVirtualUnAired": False,
|
||||
"IsMissing": False,
|
||||
"Fields": "SpecialEpisodeNumbers,{}".format(get_default_filters())
|
||||
}
|
||||
|
||||
url = get_jellyfin_url(url_path, url_params)
|
||||
|
||||
plugin_params = {
|
||||
"url": url,
|
||||
"mode": "GET_CONTENT",
|
||||
"media_type": "Season"
|
||||
}
|
||||
|
||||
action_params = urlencode(plugin_params)
|
||||
|
||||
action_url = "plugin://{}/?{}".format(addon_id, action_params)
|
||||
built_in_command = 'ActivateWindow(Videos, {}, return)'.format(
|
||||
action_url
|
||||
)
|
||||
xbmc.executebuiltin(built_in_command)
|
||||
|
||||
elif selected_action == "view_series":
|
||||
@@ -596,18 +625,30 @@ def show_menu(params):
|
||||
if not series_id:
|
||||
series_id = item_id
|
||||
|
||||
u = ('/Shows/' + series_id +
|
||||
'/Seasons'
|
||||
'?userId={}'.format(api.user_id) +
|
||||
'&Fields={}'.format(get_default_filters()) +
|
||||
'&format=json')
|
||||
url_path = "/Shows/{}/Seasons".format(series_id)
|
||||
url_params = {
|
||||
"userId": api.user_id,
|
||||
"Fields": get_default_filters(),
|
||||
}
|
||||
|
||||
action_url = ("plugin://plugin.video.jellycon/?url=" + quote(u) + "&mode=GET_CONTENT&media_type=Series")
|
||||
url = get_jellyfin_url(url_path, url_params)
|
||||
|
||||
plugin_params = {
|
||||
"url": url,
|
||||
"mode": "GET_CONTENT",
|
||||
"media_type": "Series"
|
||||
}
|
||||
|
||||
action_params = urlencode(plugin_params)
|
||||
|
||||
action_url = "plugin://{}/?{}".format(addon_id, action_params)
|
||||
|
||||
if xbmc.getCondVisibility("Window.IsActive(home)"):
|
||||
built_in_command = 'ActivateWindow(Videos, ' + action_url + ', return)'
|
||||
built_in_command = 'ActivateWindow(Videos, {}, return'.format(
|
||||
action_url
|
||||
)
|
||||
else:
|
||||
built_in_command = 'Container.Update(' + action_url + ')'
|
||||
built_in_command = 'Container.Update({})'.format(action_url)
|
||||
|
||||
xbmc.executebuiltin(built_in_command)
|
||||
|
||||
@@ -629,18 +670,21 @@ def show_content(params):
|
||||
if item_type.lower().find("movie") == -1:
|
||||
group_movies = False
|
||||
|
||||
content_url = ("/Users/{}/Items".format(api.user_id) +
|
||||
"?format=json" +
|
||||
"&ImageTypeLimit=1" +
|
||||
"&IsMissing=False" +
|
||||
"&Fields={}".format(get_default_filters()) +
|
||||
'&CollapseBoxSetItems=' + str(group_movies) +
|
||||
'&GroupItemsIntoCollections=' + str(group_movies) +
|
||||
"&Recursive=true" +
|
||||
'&SortBy=Name' +
|
||||
'&SortOrder=Ascending' +
|
||||
"&IsVirtualUnaired=false" +
|
||||
"&IncludeItemTypes=" + item_type)
|
||||
url_path = "/Users/{}/Items".format(api.user_id)
|
||||
url_params = {
|
||||
"ImageTypeLimit": 1,
|
||||
"IsMissing": False,
|
||||
"Fields": get_default_filters(),
|
||||
"CollapseBoxSetItems": group_movies,
|
||||
"GroupItemsIntoCollections": group_movies,
|
||||
"Recursive": True,
|
||||
"SortBy": "Name",
|
||||
"SortOrder": "Ascending",
|
||||
"IsVirtualUnaired": False,
|
||||
"IncludeItemTypes": item_type
|
||||
}
|
||||
|
||||
content_url = get_jellyfin_url(url_path, url_params)
|
||||
|
||||
log.debug("showContent Content Url: {0}".format(content_url))
|
||||
get_content(content_url, params)
|
||||
@@ -651,15 +695,21 @@ def search_results_person(params):
|
||||
handle = int(sys.argv[1])
|
||||
|
||||
person_id = params.get("person_id")
|
||||
details_url = ('/Users/{}/Items'.format(api.user_id) +
|
||||
'?PersonIds=' + person_id +
|
||||
'&Recursive=true' +
|
||||
'&Fields={}'.format(get_default_filters()) +
|
||||
'&format=json')
|
||||
|
||||
url_path = "/Users/{}/Items".format(api.user_id)
|
||||
url_params = {
|
||||
"PersonIds": person_id,
|
||||
"Recursive": True,
|
||||
"Fields": get_default_filters()
|
||||
}
|
||||
|
||||
details_url = get_jellyfin_url(url_path, url_params)
|
||||
|
||||
params["name_format"] = "Episode|episode_name_format"
|
||||
|
||||
dir_items, detected_type, total_records = process_directory(details_url, None, params)
|
||||
dir_items, detected_type, total_records = process_directory(
|
||||
details_url, None, params
|
||||
)
|
||||
|
||||
log.debug('search_results_person results: {0}'.format(dir_items))
|
||||
log.debug('search_results_person detect_type: {0}'.format(detected_type))
|
||||
@@ -675,7 +725,7 @@ def search_results_person(params):
|
||||
content_type = 'episodes'
|
||||
elif detected_type == "Series":
|
||||
content_type = 'tvshows'
|
||||
elif detected_type == "Music" or detected_type == "Audio" or detected_type == "Musicalbum":
|
||||
elif detected_type in ["Music", "Audio", "Musicalbum"]:
|
||||
content_type = 'songs'
|
||||
|
||||
if content_type:
|
||||
@@ -708,7 +758,7 @@ def search_results(params):
|
||||
heading_type = translate_string(30235)
|
||||
content_type = 'episodes'
|
||||
params["name_format"] = "Episode|episode_name_format"
|
||||
elif item_type == "music" or item_type == "audio" or item_type == "musicalbum":
|
||||
elif item_type in ["music", "audio", "musicalalbum"]:
|
||||
heading_type = 'Music'
|
||||
content_type = 'songs'
|
||||
elif item_type == "person":
|
||||
@@ -724,7 +774,9 @@ def search_results(params):
|
||||
home_window = HomeWindow()
|
||||
last_search = home_window.get_property("last_search")
|
||||
kb = xbmc.Keyboard()
|
||||
kb.setHeading(heading_type.capitalize() + ' ' + translate_string(30246).lower())
|
||||
kb.setHeading("{} {}".format(
|
||||
heading_type.capitalize(), translate_string(30246).lower()
|
||||
))
|
||||
kb.setDefault(last_search)
|
||||
kb.doModal()
|
||||
|
||||
@@ -756,19 +808,23 @@ def search_results(params):
|
||||
|
||||
# what type of search
|
||||
if item_type == "person":
|
||||
search_url = ("/Persons" +
|
||||
"?searchTerm=" + query +
|
||||
"&IncludePeople=true" +
|
||||
"&IncludeMedia=false" +
|
||||
"&IncludeGenres=false" +
|
||||
"&IncludeStudios=false" +
|
||||
"&IncludeArtists=false" +
|
||||
"&Limit=16" +
|
||||
"&Fields=PrimaryImageAspectRatio,BasicSyncInfo,ProductionYear" +
|
||||
"&Recursive=true" +
|
||||
"&EnableTotalRecordCount=false" +
|
||||
"&ImageTypeLimit=1" +
|
||||
"&userId={}".format(api.user_id))
|
||||
url_path = "/Persons"
|
||||
url_params = {
|
||||
"searchTerm": query,
|
||||
"IncludePeople": True,
|
||||
"IncludeMedia": False,
|
||||
"IncludeGenres": False,
|
||||
"IncludeStudios": False,
|
||||
"IncludeArtists": False,
|
||||
"Limit": 16,
|
||||
"Fields": "PrimaryImageAspectRatio,BasicSyncInfo,ProductionYear",
|
||||
"Recursive": True,
|
||||
"EnableTotalRecordCount": False,
|
||||
"ImageTypeLimit": 1,
|
||||
"userId": api.user_id
|
||||
}
|
||||
|
||||
search_url = get_jellyfin_url(url_path, url_params)
|
||||
|
||||
person_search_results = api.get(search_url)
|
||||
log.debug("Person Search Result : {0}".format(person_search_results))
|
||||
@@ -784,7 +840,9 @@ def search_results(params):
|
||||
person_name = item.get('Name')
|
||||
person_thumbnail = get_art_url(item, "Primary", server=server)
|
||||
|
||||
action_url = sys.argv[0] + "?mode=NEW_SEARCH_PERSON&person_id=" + person_id
|
||||
action_url = "{}?mode=NEW_SEARCH_PERSON&person_id={}".format(
|
||||
addon_id, person_id
|
||||
)
|
||||
|
||||
list_item = xbmcgui.ListItem(label=person_name, offscreen=True)
|
||||
list_item.setProperty("id", person_id)
|
||||
@@ -804,23 +862,29 @@ def search_results(params):
|
||||
xbmcplugin.endOfDirectory(handle, cacheToDisc=False)
|
||||
|
||||
else:
|
||||
search_url = ("/Users/{}/Items".format(api.user_id) +
|
||||
"?searchTerm=" + query +
|
||||
"&IncludePeople=false" +
|
||||
"&IncludeMedia=true" +
|
||||
"&IncludeGenres=false" +
|
||||
"&IncludeStudios=false" +
|
||||
"&IncludeArtists=false" +
|
||||
"&IncludeItemTypes=" + item_type +
|
||||
"&Limit=16" +
|
||||
"&Fields={}".format(get_default_filters()) +
|
||||
"&Recursive=true" +
|
||||
"&EnableTotalRecordCount=false" +
|
||||
"&ImageTypeLimit=1")
|
||||
url_path = "/Users/{}/Items".format(api.user_id)
|
||||
url_params = {
|
||||
"searchTerm": query,
|
||||
"IncludePeople": False,
|
||||
"IncludeMedia": True,
|
||||
"IncludeGenres": False,
|
||||
"IncludeStudios": False,
|
||||
"IncludeArtists": False,
|
||||
"IncludeItemTypes": item_type,
|
||||
"Limit": 16,
|
||||
"Fields": get_default_filters(),
|
||||
"Recursive": True,
|
||||
"EnableTotalRecordCount": False,
|
||||
"ImageTypeLimit": 1
|
||||
}
|
||||
|
||||
search_url = get_jellyfin_url(url_path, url_params)
|
||||
|
||||
# set content type
|
||||
xbmcplugin.setContent(handle, content_type)
|
||||
dir_items, detected_type, total_records = process_directory(search_url, progress, params)
|
||||
dir_items, detected_type, total_records = process_directory(
|
||||
search_url, progress, params
|
||||
)
|
||||
xbmcplugin.addDirectoryItems(handle, dir_items)
|
||||
xbmcplugin.endOfDirectory(handle, cacheToDisc=False)
|
||||
|
||||
@@ -880,7 +944,9 @@ def play_action(params):
|
||||
def play_item_trailer(item_id):
|
||||
log.debug("== ENTER: playTrailer ==")
|
||||
|
||||
url = "/Users/{}/Items/{}/LocalTrailers?format=json".format(user_details.get('user_id'), item_id)
|
||||
url = "/Users/{}/Items/{}/LocalTrailers?format=json".format(
|
||||
user_details.get('user_id'), item_id
|
||||
)
|
||||
|
||||
result = api.get(url)
|
||||
|
||||
@@ -897,7 +963,7 @@ def play_item_trailer(item_id):
|
||||
info["type"] = "local"
|
||||
name = trailer.get("Name")
|
||||
while not name or name in trailer_names:
|
||||
name = "Trailer " + str(count)
|
||||
name = "Trailer {}".format(count)
|
||||
count += 1
|
||||
info["name"] = name
|
||||
info["id"] = trailer.get("Id")
|
||||
@@ -905,7 +971,9 @@ def play_item_trailer(item_id):
|
||||
trailer_names.append(name)
|
||||
trailer_list.append(info)
|
||||
|
||||
url = "/Users/{}/Items/{}?format=json&Fields=RemoteTrailers".format(user_details.get('user_id'), item_id)
|
||||
url = "/Users/{}/Items/{}?format=json&Fields=RemoteTrailers".format(
|
||||
user_details.get("user_id"), item_id
|
||||
)
|
||||
result = api.get(url)
|
||||
log.debug("RemoteTrailers: {0}".format(result))
|
||||
count = 1
|
||||
@@ -922,7 +990,7 @@ def play_item_trailer(item_id):
|
||||
info["url"] = url
|
||||
name = trailer.get("Name")
|
||||
while not name or name in trailer_names:
|
||||
name = "Trailer " + str(count)
|
||||
name = "Trailer {}".format(count)
|
||||
count += 1
|
||||
info["name"] = name
|
||||
trailer_names.append(name)
|
||||
@@ -932,7 +1000,9 @@ def play_item_trailer(item_id):
|
||||
|
||||
trailer_text = []
|
||||
for trailer in trailer_list:
|
||||
name = trailer.get("name") + " (" + trailer.get("type") + ")"
|
||||
name = "{} ({})".format(
|
||||
trailer.get("name"), trailer.get("type")
|
||||
)
|
||||
trailer_text.append(name)
|
||||
|
||||
dialog = xbmcgui.Dialog()
|
||||
@@ -948,7 +1018,8 @@ def play_item_trailer(item_id):
|
||||
|
||||
elif trailer.get("type") == "remote":
|
||||
youtube_id = trailer.get("url").rsplit('=', 1)[1]
|
||||
youtube_plugin = "RunPlugin(plugin://plugin.video.youtube/play/?video_id=%s)" % youtube_id
|
||||
log.debug("youtube_plugin: {0}".format(youtube_plugin))
|
||||
url_root = "plugin.video.youtube/play/?video_id="
|
||||
play_url = "RunPlugin(plugin://{}{})".format(url_root, youtube_id)
|
||||
log.debug("youtube_plugin: {0}".format(play_url))
|
||||
|
||||
xbmc.executebuiltin(youtube_plugin)
|
||||
xbmc.executebuiltin(play_url)
|
||||
|
||||
@@ -42,7 +42,9 @@ class LogHandler(logging.StreamHandler):
|
||||
string = self.format(record)
|
||||
|
||||
# Hide server URL in logs
|
||||
string = string.replace(self.server or "{server}", "{jellyfin-server}")
|
||||
string = string.replace(
|
||||
self.server or "{server}", "{jellyfin-server}"
|
||||
)
|
||||
|
||||
py_version = sys.version_info.major
|
||||
# Log level notation changed in Kodi v19
|
||||
@@ -70,12 +72,17 @@ class LogHandler(logging.StreamHandler):
|
||||
|
||||
class MyFormatter(logging.Formatter):
|
||||
|
||||
def __init__(self, fmt='%(name)s -> %(levelname)s::%(relpath)s:%(lineno)s %(message)s'):
|
||||
def __init__(
|
||||
self,
|
||||
fmt='%(name)s -> %(levelname)s::%(relpath)s:%(lineno)s %(message)s'
|
||||
):
|
||||
logging.Formatter.__init__(self, fmt)
|
||||
|
||||
def format(self, record):
|
||||
if record.pathname:
|
||||
record.pathname = ensure_text(record.pathname, get_filesystem_encoding())
|
||||
record.pathname = ensure_text(
|
||||
record.pathname, get_filesystem_encoding()
|
||||
)
|
||||
|
||||
self._gen_rel_path(record)
|
||||
|
||||
@@ -92,7 +99,10 @@ class MyFormatter(logging.Formatter):
|
||||
o = ensure_text(o, get_filesystem_encoding())
|
||||
|
||||
if o.startswith(' File "'):
|
||||
# If this split can't handle your file names, you should seriously consider renaming your files.
|
||||
"""
|
||||
If this split can't handle your file names,
|
||||
you should seriously consider renaming your files.
|
||||
"""
|
||||
fn = o.split(' File "', 2)[1].split('", line ', 1)[0]
|
||||
rfn = os.path.realpath(fn)
|
||||
if rfn.startswith(_pluginpath_real):
|
||||
|
||||
@@ -26,7 +26,11 @@ class ContextMonitor(threading.Thread):
|
||||
|
||||
while not xbmc.Monitor().abortRequested() and not self.stop_thread:
|
||||
|
||||
if xbmc.getCondVisibility("Window.IsActive(fullscreenvideo) | Window.IsActive(visualisation)"):
|
||||
visibility_check = (
|
||||
"Window.IsActive(fullscreenvideo) | "
|
||||
"Window.IsActive(visualisation)"
|
||||
)
|
||||
if xbmc.getCondVisibility(visibility_check):
|
||||
xbmc.sleep(1000)
|
||||
else:
|
||||
if xbmc.getCondVisibility("Window.IsVisible(contextmenu)"):
|
||||
@@ -37,7 +41,9 @@ class ContextMonitor(threading.Thread):
|
||||
show_menu(params)
|
||||
|
||||
container_id = xbmc.getInfoLabel("System.CurrentControlID")
|
||||
item_id = xbmc.getInfoLabel("Container(" + str(container_id) + ").ListItem.Property(id)")
|
||||
item_id = xbmc.getInfoLabel(
|
||||
"Container({}).ListItem.Property(id)".format(container_id)
|
||||
)
|
||||
|
||||
xbmc.sleep(100)
|
||||
|
||||
|
||||
@@ -50,10 +50,10 @@ def show_server_sessions():
|
||||
now_playing = session.get("NowPlayingItem", None)
|
||||
transcoding_info = session.get("TranscodingInfo", None)
|
||||
|
||||
session_info = user_name + " - " + client_name
|
||||
session_info = "{} - {}".format(user_name, client_name)
|
||||
user_session_details = ""
|
||||
|
||||
percenatge_played = 0
|
||||
percentage_played = 0
|
||||
position_ticks = 0
|
||||
runtime = 0
|
||||
play_method = "na"
|
||||
@@ -68,37 +68,50 @@ def show_server_sessions():
|
||||
|
||||
runtime = now_playing.get("RunTimeTicks", 0)
|
||||
if position_ticks > 0 and runtime > 0:
|
||||
percenatge_played = (position_ticks / float(runtime)) * 100.0
|
||||
percenatge_played = int(percenatge_played)
|
||||
percentage_played = (position_ticks / float(runtime)) * 100.0
|
||||
percentage_played = int(percentage_played)
|
||||
|
||||
session_info += " (" + now_playing.get("Name", "na") + " " + str(percenatge_played) + "%)"
|
||||
user_session_details += now_playing.get("Name", "na") + " " + str(percenatge_played) + "%" + "\n"
|
||||
session_info += " {} {}%".format(
|
||||
now_playing.get("Name", "na"), percentage_played
|
||||
)
|
||||
user_session_details += "{} {}%\n".format(
|
||||
now_playing.get("Name", "na"), percentage_played
|
||||
)
|
||||
|
||||
else:
|
||||
session_info += " (idle)"
|
||||
user_session_details += "Idle" + "\n"
|
||||
user_session_details += "Idle\n"
|
||||
|
||||
transcoding_details = ""
|
||||
if transcoding_info:
|
||||
if not transcoding_info.get("IsVideoDirect", None):
|
||||
transcoding_details += "Video:" + transcoding_info.get("VideoCodec", "") + ":" + str(transcoding_info.get("Width", 0)) + "x" + str(transcoding_info.get("Height", 0)) + "\n"
|
||||
transcoding_details += "Video:{}:{}x{}\n".format(
|
||||
transcoding_info.get("VideoCodec", ""),
|
||||
transcoding_info.get("Width", 0),
|
||||
transcoding_info.get("Height", 0)
|
||||
)
|
||||
else:
|
||||
transcoding_details += "Video:direct\n"
|
||||
|
||||
if not transcoding_info.get("IsAudioDirect", None):
|
||||
transcoding_details += "Audio:" + transcoding_info.get("AudioCodec", "") + ":" + str(transcoding_info.get("AudioChannels", 0)) + "\n"
|
||||
transcoding_details += "Audio:{}:{}\n".format(
|
||||
transcoding_info.get("AudioCodec", ""),
|
||||
transcoding_info.get("AudioChannels", 0)
|
||||
)
|
||||
else:
|
||||
transcoding_details += "Audio:direct\n"
|
||||
|
||||
transcoding_details += "Bitrate:" + str(transcoding_info.get("Bitrate", 0)) + "\n"
|
||||
transcoding_details += "Bitrate:{}\n".format(
|
||||
transcoding_info.get("Bitrate", 0)
|
||||
)
|
||||
|
||||
list_item = xbmcgui.ListItem(label=session_info)
|
||||
list_item.setArt(art)
|
||||
|
||||
user_session_details += device_name + "(" + client_version + ")\n"
|
||||
user_session_details += client_name + "\n"
|
||||
user_session_details += play_method + "\n"
|
||||
user_session_details += transcoding_details + "\n"
|
||||
user_session_details += "{}({})\n".format(device_name, client_version)
|
||||
user_session_details += "{}\n".format(client_name)
|
||||
user_session_details += "{}\n".format(play_method)
|
||||
user_session_details += "{}\n".format(transcoding_details)
|
||||
|
||||
info_labels = {}
|
||||
info_labels["duration"] = str(runtime / 10000000)
|
||||
@@ -108,7 +121,7 @@ def show_server_sessions():
|
||||
|
||||
list_item.setProperty('TotalTime', str(runtime / 10000000))
|
||||
list_item.setProperty('ResumeTime', str(position_ticks / 10000000))
|
||||
list_item.setProperty("complete_percentage", str(percenatge_played))
|
||||
list_item.setProperty("complete_percentage", str(percentage_played))
|
||||
|
||||
item_tuple = ("", list_item, False)
|
||||
list_items.append(item_tuple)
|
||||
|
||||
@@ -20,9 +20,11 @@ def clone_default_skin():
|
||||
xbmc.executebuiltin("Dialog.Close(all,true)")
|
||||
xbmc.executebuiltin("ActivateWindow(Home)")
|
||||
|
||||
response = xbmcgui.Dialog().yesno("JellyCon Skin Cloner",
|
||||
"This will clone the default Estuary Kodi skin and add JellyCon functionality to it.",
|
||||
"Do you want to continue?")
|
||||
response = xbmcgui.Dialog().yesno(
|
||||
"JellyCon Skin Cloner",
|
||||
("This will clone the default Estuary Kodi skin and"
|
||||
"add JellyCon functionality to it."),
|
||||
"Do you want to continue?")
|
||||
if not response:
|
||||
return
|
||||
|
||||
@@ -63,7 +65,9 @@ def clone_skin():
|
||||
log.debug("Found Path: {0}".format(found))
|
||||
|
||||
kodi_home_path = translate_path("special://home")
|
||||
kodi_skin_destination = os.path.join(kodi_home_path, "addons", "skin.estuary_jellycon")
|
||||
kodi_skin_destination = os.path.join(
|
||||
kodi_home_path, "addons", "skin.estuary_jellycon"
|
||||
)
|
||||
log.debug("Kodi Skin Destination: {0}".format(kodi_skin_destination))
|
||||
|
||||
# copy all skin files (clone)
|
||||
@@ -71,7 +75,7 @@ def clone_skin():
|
||||
total = len(all_files)
|
||||
for skin_file in all_files:
|
||||
percentage_done = int(float(count) / float(total) * 100.0)
|
||||
pdialog.update(percentage_done, "%s" % skin_file)
|
||||
pdialog.update(percentage_done, skin_file)
|
||||
|
||||
source = os.path.join(kodi_skin_source, skin_file)
|
||||
destination = os.path.join(kodi_skin_destination, skin_file)
|
||||
@@ -90,7 +94,9 @@ def clone_skin():
|
||||
addon_tree.write(addon_xml_path)
|
||||
|
||||
# get jellycon path
|
||||
jellycon_path = os.path.join(kodi_home_path, "addons", "plugin.video.jellycon")
|
||||
jellycon_path = os.path.join(
|
||||
kodi_home_path, "addons", "plugin.video.jellycon"
|
||||
)
|
||||
|
||||
log.debug("Major Version: {0}".format(kodi_version()))
|
||||
|
||||
@@ -102,7 +108,10 @@ def clone_skin():
|
||||
|
||||
# Copy customized skin files from our addon into cloned skin
|
||||
for file_name in file_list:
|
||||
source = os.path.join(jellycon_path, "resources", "skins", "skin.estuary", str(kodi_version), "xml", file_name)
|
||||
source = os.path.join(
|
||||
jellycon_path, "resources", "skins", "skin.estuary",
|
||||
str(kodi_version), "xml", file_name
|
||||
)
|
||||
destination = os.path.join(kodi_skin_destination, "xml", file_name)
|
||||
xbmcvfs.copy(source, destination)
|
||||
|
||||
@@ -111,7 +120,10 @@ def clone_skin():
|
||||
pdialog.close()
|
||||
del pdialog
|
||||
|
||||
response = xbmcgui.Dialog().yesno("JellyCon Skin Cloner", "Do you want to switch to the new cloned skin?")
|
||||
response = xbmcgui.Dialog().yesno(
|
||||
"JellyCon Skin Cloner",
|
||||
"Do you want to switch to the new cloned skin?"
|
||||
)
|
||||
if not response:
|
||||
return
|
||||
|
||||
@@ -122,10 +134,14 @@ def clone_skin():
|
||||
result = JsonRpc('Addons.SetAddonEnabled').execute(params)
|
||||
log.debug("Addons.SetAddonEnabled : {0}".format(result))
|
||||
|
||||
log.debug("SkinCloner : Current Skin : " + get_value("lookandfeel.skin"))
|
||||
log.debug("SkinCloner : Current Skin : {}".format(
|
||||
get_value("lookandfeel.skin"))
|
||||
)
|
||||
set_result = set_value("lookandfeel.skin", "skin.estuary_jellycon")
|
||||
log.debug("Save Setting : lookandfeel.skin : {0}".format(set_result))
|
||||
log.debug("SkinCloner : Current Skin : " + get_value("lookandfeel.skin"))
|
||||
log.debug("SkinCloner : Current Skin : {}".format(
|
||||
get_value("lookandfeel.skin"))
|
||||
)
|
||||
|
||||
|
||||
def update_kodi_settings():
|
||||
|
||||
@@ -30,6 +30,8 @@ def timer(func):
|
||||
data = args[1]
|
||||
elif func.__name__ == "main_entry_point" and len(sys.argv) > 2:
|
||||
data = sys.argv[2]
|
||||
log.info("timing_data|{0}|{1}|{2}|{3}".format(func.__name__, started, ended, data))
|
||||
log.info("timing_data|{0}|{1}|{2}|{3}".format(
|
||||
func.__name__, started, ended, data)
|
||||
)
|
||||
return value
|
||||
return wrapper
|
||||
|
||||
@@ -41,7 +41,8 @@ def kodi_version():
|
||||
else:
|
||||
default_versionstring = "19.1 (19.1.0) Git:20210509-85e05228b4"
|
||||
|
||||
version_string = xbmc.getInfoLabel('System.BuildVersion') or default_versionstring
|
||||
version_string = xbmc.getInfoLabel(
|
||||
'System.BuildVersion') or default_versionstring
|
||||
return int(version_string.split(' ', 1)[0].split('.', 1)[0])
|
||||
|
||||
|
||||
@@ -53,7 +54,7 @@ def get_jellyfin_url(path, params):
|
||||
|
||||
def get_checksum(item):
|
||||
userdata = item['UserData']
|
||||
checksum = "%s_%s_%s_%s_%s_%s_%s" % (
|
||||
checksum = "{}_{}_{}_{}_{}_{}_{}".format(
|
||||
item['Etag'],
|
||||
userdata['Played'],
|
||||
userdata['IsFavorite'],
|
||||
@@ -82,14 +83,15 @@ def send_event_notification(method, data=None, hexlify=False):
|
||||
Send events through Kodi's notification system
|
||||
'''
|
||||
data = data or {}
|
||||
data_str = json.dumps(data)
|
||||
|
||||
if hexlify:
|
||||
# Used exclusively for the upnext plugin
|
||||
data = ensure_text(binascii.hexlify(ensure_binary(json.dumps(data))))
|
||||
data_str = ensure_text(binascii.hexlify(ensure_binary(data_str)))
|
||||
sender = 'plugin.video.jellycon'
|
||||
data = '"[%s]"' % json.dumps(data).replace('"', '\\"')
|
||||
data = '"[{}]"'.format(data_str.replace('"', '\\"'))
|
||||
|
||||
xbmc.executebuiltin('NotifyAll(%s, %s, %s)' % (sender, method, data))
|
||||
xbmc.executebuiltin('NotifyAll({}, {}, {})'.format(sender, method, data))
|
||||
|
||||
|
||||
def datetime_from_string(time_string):
|
||||
@@ -98,15 +100,22 @@ def datetime_from_string(time_string):
|
||||
if time_string[-1:] == "Z":
|
||||
time_string = re.sub("[0-9]{1}Z", " UTC", time_string)
|
||||
elif time_string[-6:] == "+00:00":
|
||||
time_string = re.sub("[0-9]{1}\+00:00", " UTC", time_string) # noqa: W605
|
||||
time_string = re.sub(
|
||||
"[0-9]{1}\+00:00", " UTC", time_string # noqa: W605
|
||||
)
|
||||
|
||||
try:
|
||||
dt = datetime.strptime(time_string, "%Y-%m-%dT%H:%M:%S.%f %Z")
|
||||
except TypeError:
|
||||
# https://bugs.python.org/issue27400
|
||||
dt = datetime(*(time.strptime(time_string, "%Y-%m-%dT%H:%M:%S.%f %Z")[0:6]))
|
||||
dt = datetime(*(
|
||||
time.strptime(time_string, "%Y-%m-%dT%H:%M:%S.%f %Z")[0:6])
|
||||
)
|
||||
|
||||
# Dates received from the server are in UTC, but parsing them results in naive objects
|
||||
"""
|
||||
Dates received from the server are in UTC, but parsing them results
|
||||
in naive objects
|
||||
"""
|
||||
utc = tz.tzutc()
|
||||
utc_dt = dt.replace(tzinfo=utc)
|
||||
|
||||
@@ -129,7 +138,7 @@ def convert_size(size_bytes):
|
||||
i = int(math.floor(math.log(size_bytes, 1024)))
|
||||
p = math.pow(1024, i)
|
||||
s = round(size_bytes / p, 2)
|
||||
return "%s %s" % (s, size_name[i])
|
||||
return "{} {}".format(s, size_name[i])
|
||||
|
||||
|
||||
def translate_string(string_id):
|
||||
@@ -155,7 +164,9 @@ def get_device_id():
|
||||
rand_id = uuid4().hex
|
||||
return '{}-{}'.format(client_id, rand_id)
|
||||
|
||||
jellyfin_guid_path = py2_decode(translate_path("special://temp/jellycon_guid"))
|
||||
jellyfin_guid_path = py2_decode(
|
||||
translate_path("special://temp/jellycon_guid")
|
||||
)
|
||||
log.debug("jellyfin_guid_path: {0}".format(jellyfin_guid_path))
|
||||
guid = xbmcvfs.File(jellyfin_guid_path)
|
||||
client_id = guid.read()
|
||||
@@ -183,7 +194,8 @@ def get_version():
|
||||
|
||||
def save_user_details(user_name, user_id, token):
|
||||
settings = xbmcaddon.Addon()
|
||||
save_user_to_settings = settings.getSetting('save_user_to_settings') == 'true'
|
||||
save_user_to_settings = settings.getSetting(
|
||||
'save_user_to_settings') == 'true'
|
||||
addon_data = translate_path(xbmcaddon.Addon().getAddonInfo('profile'))
|
||||
|
||||
# Save to a config file for reference later if desired
|
||||
@@ -201,7 +213,8 @@ def save_user_details(user_name, user_id, token):
|
||||
}
|
||||
|
||||
with open(os.path.join(addon_data, 'auth.json'), 'wb') as outfile:
|
||||
data = json.dumps(auth_data, sort_keys=True, indent=4, ensure_ascii=False)
|
||||
data = json.dumps(
|
||||
auth_data, sort_keys=True, indent=4, ensure_ascii=False)
|
||||
if isinstance(data, text_type):
|
||||
data = data.encode('utf-8')
|
||||
outfile.write(data)
|
||||
@@ -219,10 +232,10 @@ def load_user_details():
|
||||
user_name = window.get_property('user_name')
|
||||
if not user_name:
|
||||
user_name = settings.getSetting('username')
|
||||
save_user_to_settings = settings.getSetting('save_user_to_settings') == 'true'
|
||||
save_user = settings.getSetting('save_user_to_settings') == 'true'
|
||||
addon_data = translate_path(xbmcaddon.Addon().getAddonInfo('profile'))
|
||||
|
||||
if save_user_to_settings:
|
||||
if save_user:
|
||||
try:
|
||||
with open(os.path.join(addon_data, 'auth.json'), 'rb') as infile:
|
||||
auth_data = json.load(infile)
|
||||
@@ -251,9 +264,9 @@ def load_user_details():
|
||||
|
||||
def get_saved_users():
|
||||
settings = xbmcaddon.Addon()
|
||||
save_user_to_settings = settings.getSetting('save_user_to_settings') == 'true'
|
||||
save_user = settings.getSetting('save_user_to_settings') == 'true'
|
||||
addon_data = translate_path(xbmcaddon.Addon().getAddonInfo('profile'))
|
||||
if not save_user_to_settings:
|
||||
if not save_user:
|
||||
return []
|
||||
|
||||
try:
|
||||
@@ -316,12 +329,13 @@ def get_art_url(data, art_type, parent=False, index=0, server=None):
|
||||
if image_tag_type:
|
||||
image_tag = image_tag_type
|
||||
elif parent is True:
|
||||
if (item_type == "Episode" or item_type == "Season") and art_type == 'Primary':
|
||||
if ((item_type == "Episode" or item_type == "Season") and
|
||||
art_type == 'Primary'):
|
||||
tag_name = 'SeriesPrimaryImageTag'
|
||||
id_name = 'SeriesId'
|
||||
else:
|
||||
tag_name = 'Parent%sImageTag' % art_type
|
||||
id_name = 'Parent%sItemId' % art_type
|
||||
tag_name = 'Parent{}ImageTag'.format(art_type)
|
||||
id_name = 'Parent{}ItemId'.format(art_type)
|
||||
parent_image_id = data.get(id_name)
|
||||
parent_image_tag = data.get(tag_name)
|
||||
if parent_image_id is not None and parent_image_tag is not None:
|
||||
@@ -329,7 +343,9 @@ def get_art_url(data, art_type, parent=False, index=0, server=None):
|
||||
image_tag = parent_image_tag
|
||||
|
||||
# ParentTag not passed for Banner and Art
|
||||
if not image_tag and not ((art_type == 'Banner' or art_type == 'Art') and parent is True):
|
||||
if (not image_tag and
|
||||
not ((art_type == 'Banner' or art_type == 'Art') and
|
||||
parent is True)):
|
||||
return ""
|
||||
|
||||
artwork = "{}/Items/{}/Images/{}/{}?Format=original&Tag={}".format(
|
||||
@@ -340,7 +356,9 @@ def get_art_url(data, art_type, parent=False, index=0, server=None):
|
||||
def image_url(item_id, art_type, index, width, height, image_tag, server):
|
||||
|
||||
# test imageTag e3ab56fe27d389446754d0fb04910a34
|
||||
artwork = "{}/Items/{}/Images/{}/{}?Format=original&Tag={}".format(server, item_id, art_type, index, image_tag)
|
||||
artwork = "{}/Items/{}/Images/{}/{}?Format=original&Tag={}".format(
|
||||
server, item_id, art_type, index, image_tag
|
||||
)
|
||||
if int(width) > 0:
|
||||
artwork += '&MaxWidth={}'.format(width)
|
||||
if int(height) > 0:
|
||||
@@ -413,7 +431,9 @@ def download_external_sub(language, codec, url):
|
||||
|
||||
# Write the subtitle file to the local filesystem
|
||||
file_name = 'Stream.{}.{}'.format(language, codec)
|
||||
file_path = py2_decode(translate_path('special://temp/{}'.format(file_name)))
|
||||
file_path = py2_decode(
|
||||
translate_path('special://temp/{}'.format(file_name))
|
||||
)
|
||||
with open(file_path, 'wb') as f:
|
||||
f.write(r.content)
|
||||
|
||||
|
||||
@@ -157,7 +157,9 @@ class WebSocketClient(threading.Thread):
|
||||
|
||||
elif command == 'SetVolume':
|
||||
volume = arguments['Volume']
|
||||
xbmc.executebuiltin('SetVolume(%s[,showvolumebar])' % volume)
|
||||
xbmc.executebuiltin(
|
||||
'SetVolume({}[,showvolumebar])'.format(volume)
|
||||
)
|
||||
|
||||
elif command == 'SetAudioStreamIndex':
|
||||
index = int(arguments['Index'])
|
||||
@@ -169,7 +171,7 @@ class WebSocketClient(threading.Thread):
|
||||
|
||||
elif command == 'SetRepeatMode':
|
||||
mode = arguments['RepeatMode']
|
||||
xbmc.executebuiltin('xbmc.PlayerControl(%s)' % mode)
|
||||
xbmc.executebuiltin('xbmc.PlayerControl({})'.format(mode))
|
||||
|
||||
elif command == 'DisplayMessage':
|
||||
|
||||
@@ -252,7 +254,9 @@ class WebSocketClient(threading.Thread):
|
||||
else:
|
||||
server = server.replace('http://', 'ws://')
|
||||
|
||||
websocket_url = "%s/socket?api_key=%s&deviceId=%s" % (server, token, self.device_id)
|
||||
websocket_url = "{}/socket?api_key={}&deviceId={}".format(
|
||||
server, token, self.device_id
|
||||
)
|
||||
log.debug("websocket url: {0}".format(websocket_url))
|
||||
|
||||
self._client = websocket.WebSocketApp(
|
||||
|
||||
@@ -83,8 +83,9 @@ def set_background_image(force=False):
|
||||
background_items = []
|
||||
|
||||
if len(background_items) == 0:
|
||||
log.debug("set_background_image: Need to load more backgrounds {0} - {1}".format(
|
||||
len(background_items), background_current_item))
|
||||
log.debug("Need to load more backgrounds {0} - {1}".format(
|
||||
len(background_items), background_current_item)
|
||||
)
|
||||
|
||||
url_params = {}
|
||||
url_params["Recursive"] = True
|
||||
@@ -112,13 +113,17 @@ def set_background_image(force=False):
|
||||
background_items.append(item_background)
|
||||
|
||||
log.debug("set_background_image: Loaded {0} more backgrounds".format(
|
||||
len(background_items)))
|
||||
len(background_items))
|
||||
)
|
||||
|
||||
if len(background_items) > 0:
|
||||
bg_image = background_items[background_current_item].get("image")
|
||||
label = background_items[background_current_item].get("name")
|
||||
log.debug(
|
||||
"set_background_image: {0} - {1} - {2}".format(background_current_item, label, bg_image))
|
||||
"set_background_image: {0} - {1} - {2}".format(
|
||||
background_current_item, label, bg_image
|
||||
)
|
||||
)
|
||||
|
||||
background_current_item += 1
|
||||
if background_current_item >= len(background_items):
|
||||
@@ -177,7 +182,9 @@ def check_for_new_content():
|
||||
url_params["IncludeItemTypes"] = "Movie,Episode"
|
||||
url_params["ImageTypeLimit"] = 0
|
||||
|
||||
played_url = get_jellyfin_url('/Users/{}/Items'.format(user_id), url_params)
|
||||
played_url = get_jellyfin_url(
|
||||
'/Users/{}/Items'.format(user_id), url_params
|
||||
)
|
||||
|
||||
result = api.get(played_url)
|
||||
log.debug("LATEST_PLAYED_ITEM: {0}".format(result))
|
||||
@@ -221,7 +228,9 @@ def get_widget_content_cast(handle, params):
|
||||
if not result:
|
||||
return
|
||||
|
||||
if result.get("Type", "") in ["Episode", "Season"] and params.get("auto", "true") == "true":
|
||||
if (result.get("Type", "") in ["Episode", "Season"] and
|
||||
params.get("auto", "true") == "true"):
|
||||
|
||||
series_id = result.get("SeriesId")
|
||||
if series_id:
|
||||
params["id"] = series_id
|
||||
@@ -242,7 +251,9 @@ def get_widget_content_cast(handle, params):
|
||||
person_thumbnail = None
|
||||
if person_tag:
|
||||
person_thumbnail = image_url(
|
||||
person_id, "Primary", 0, 400, 400, person_tag, server=server)
|
||||
person_id, "Primary", 0, 400, 400,
|
||||
person_tag, server=server
|
||||
)
|
||||
|
||||
list_item = xbmcgui.ListItem(label=person_name, offscreen=True)
|
||||
|
||||
@@ -393,12 +404,19 @@ def get_widget_content(handle, params):
|
||||
while len(ids) < item_limit and suggested_items:
|
||||
items = suggested_items[set_id]
|
||||
log.debug(
|
||||
"BaselineItemName : {0} - {1}".format(set_id, items.get("BaselineItemName")))
|
||||
"BaselineItemName : {0} - {1}".format(
|
||||
set_id, items.get("BaselineItemName")
|
||||
)
|
||||
)
|
||||
items = items["Items"]
|
||||
rand = random.randint(0, len(items) - 1)
|
||||
item = items[rand]
|
||||
if item["Type"] == "Movie" and item["Id"] not in ids and (not item["UserData"]["Played"] or not hide_watched):
|
||||
|
||||
if (item["Type"] == "Movie" and item["Id"] not in ids and
|
||||
(not item["UserData"]["Played"] or not hide_watched)):
|
||||
|
||||
ids.append(item["Id"])
|
||||
|
||||
del items[rand]
|
||||
if len(items) == 0:
|
||||
del suggested_items[set_id]
|
||||
@@ -412,22 +430,23 @@ def get_widget_content(handle, params):
|
||||
|
||||
items_url = get_jellyfin_url(url_verb, url_params)
|
||||
|
||||
if url_params.get('IncludeItemTypes', '') == 'Episode' or params.get('type', '') == 'nextup_episodes':
|
||||
if (url_params.get('IncludeItemTypes', '') == 'Episode' or
|
||||
params.get('type', '') == 'nextup_episodes'):
|
||||
params["name_format"] = "Episode|episode_name_format"
|
||||
|
||||
list_items, detected_type, total_records = process_directory(
|
||||
items_url, None, params, use_cached_widget_data)
|
||||
|
||||
# Combine In Progress and Next Up Episodes, append next up after In Progress
|
||||
# Combine In Progress and Next Up Episodes, add next up after In Progress
|
||||
if widget_type == "nextup_episodes":
|
||||
inprogress_url = get_jellyfin_url(
|
||||
inprogress_url_verb, inprogress_url_params)
|
||||
|
||||
params["name_format"] = "Episode|episode_name_format"
|
||||
list_items_inprogress, detected_type, total_records = process_directory(
|
||||
inprogress, detected_type, total_records = process_directory(
|
||||
inprogress_url, None, params, use_cached_widget_data)
|
||||
|
||||
list_items = list_items_inprogress + list_items
|
||||
list_items = inprogress + list_items
|
||||
|
||||
if detected_type is not None:
|
||||
# if the media type is not set then try to use the detected type
|
||||
@@ -440,7 +459,7 @@ def get_widget_content(handle, params):
|
||||
content_type = 'episodes'
|
||||
elif detected_type == "Series":
|
||||
content_type = 'tvshows'
|
||||
elif detected_type == "Music" or detected_type == "Audio" or detected_type == "Musicalbum":
|
||||
elif detected_type in ["Music", "Audio", "Musicalbum"]:
|
||||
content_type = 'songs'
|
||||
|
||||
if content_type:
|
||||
|
||||
Reference in New Issue
Block a user