# Gnu General Public License - see LICENSE.TXT from __future__ import division, absolute_import, print_function, unicode_literals from six.moves.urllib.parse import quote, unquote, parse_qsl import sys import os import time import cProfile import pstats import json from six import StringIO import xbmcplugin import xbmcgui import xbmcaddon import xbmc from .downloadutils import DownloadUtils, load_user_details from .utils import get_art, send_event_notification, convert_size from .kodi_utils import HomeWindow from .clientinfo import ClientInformation from .datamanager import DataManager, clear_cached_server_data from .server_detect import check_server, check_connection_speed from .loghandler import LazyLogger from .menu_functions import display_main_menu, display_menu, show_movie_alpha_list, show_tvshow_alpha_list, show_genre_list, show_search, show_movie_pages from .translation import string_load from .server_sessions import show_server_sessions from .action_menu import ActionMenu from .bitrate_dialog import BitrateDialog from .safe_delete_dialog import SafeDeleteDialog from .widgets import get_widget_content, get_widget_content_cast, check_for_new_content from . import trakttokodi from .cache_images import CacheArtwork from .dir_functions import get_content, process_directory from .tracking import timer from .skin_cloner import clone_default_skin from .play_utils import play_file __addon__ = xbmcaddon.Addon() __addondir__ = xbmc.translatePath(__addon__.getAddonInfo('profile')) __cwd__ = __addon__.getAddonInfo('path') PLUGINPATH = xbmc.translatePath(os.path.join(__cwd__)) log = LazyLogger(__name__) kodi_version = int(xbmc.getInfoLabel('System.BuildVersion')[:2]) downloadUtils = DownloadUtils() dataManager = DataManager() @timer def main_entry_point(): log.debug("===== JellyCon START =====") settings = xbmcaddon.Addon() profile_count = int(settings.getSetting('profile_count')) pr = None if profile_count > 0: profile_count = profile_count - 1 settings.setSetting('profile_count', str(profile_count)) pr = cProfile.Profile() pr.enable() log.debug("Running Python: {0}".format(sys.version_info)) log.debug("Running JellyCon: {0}".format(ClientInformation().get_version())) 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)) params = get_params() log.info("Script params: {0}".format(params)) request_path = params.get("request_path", None) param_url = params.get('url', None) if param_url: param_url = unquote(param_url) mode = params.get("mode", None) if len(params) == 1 and request_path and request_path.find("/library/movies") > -1: check_server() new_params = {} new_params["item_type"] = "Movie" new_params["media_type"] = "movies" show_content(new_params) elif mode == "CHANGE_USER": check_server(change_user=True, notify=False) elif mode == "CACHE_ARTWORK": CacheArtwork().cache_artwork_interactive() elif mode == "DETECT_SERVER": check_server(force=True, notify=True) elif mode == "DETECT_SERVER_USER": check_server(force=True, change_user=True, notify=False) elif mode == "DETECT_CONNECTION_SPEED": check_connection_speed() elif mode == "playTrailer": item_id = params["id"] play_item_trailer(item_id) elif mode == "MOVIE_ALPHA": show_movie_alpha_list(params) elif mode == "TVSHOW_ALPHA": show_tvshow_alpha_list(params) elif mode == "GENRES": show_genre_list(params) elif mode == "MOVIE_PAGES": show_movie_pages(params) elif mode == "TOGGLE_WATCHED": toggle_watched(params) elif mode == "SHOW_MENU": show_menu(params) elif mode == "CLONE_SKIN": clone_default_skin() elif mode == "SHOW_SETTINGS": __addon__.openSettings() window = xbmcgui.getCurrentWindowId() if window == 10000: log.debug("Currently in home - refreshing to allow new settings to be taken") xbmc.executebuiltin("ActivateWindow(Home)") elif mode == "CLEAR_CACHE": clear_cached_server_data() elif mode == "WIDGET_CONTENT": get_widget_content(int(sys.argv[1]), params) elif mode == "WIDGET_CONTENT_CAST": get_widget_content_cast(int(sys.argv[1]), params) elif mode == "SHOW_CONTENT": check_server() show_content(params) elif mode == "SEARCH": xbmcplugin.setContent(int(sys.argv[1]), 'files') show_search() elif mode == "NEW_SEARCH": search_results(params) elif mode == "NEW_SEARCH_PERSON": search_results_person(params) elif mode == "SHOW_SERVER_SESSIONS": show_server_sessions() elif mode == "TRAKTTOKODI": trakttokodi.entry_point(params) 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)) if mode == "GET_CONTENT": get_content(param_url, params) elif mode == "PLAY": play_action(params) else: check_server() display_main_menu() if pr: pr.disable() file_time_stamp = time.strftime("%Y%m%d-%H%M%S") tab_file_name = __addondir__ + "profile(" + file_time_stamp + ").txt" s = StringIO.StringIO() ps = pstats.Stats(pr, stream=s) ps = ps.sort_stats('cumulative') ps.print_stats() ps.strip_dirs() ps = ps.sort_stats('tottime') ps.print_stats() with open(tab_file_name, 'wb') as f: f.write(s.getvalue()) 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 = "{server}/Users/{userid}/Items?fields=MediaStreams&Recursive=true" \ "&IncludeItemTypes=series&IncludeMedia=true&ImageTypeLimit=1&Limit=16" \ "&AnyProviderIdEquals=" + show_provider_ids content = dataManager.get_content(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) if item_id is None: return url = "{server}/Users/{userid}/Items/" + item_id + "?format=json" data_manager = DataManager() result = data_manager.get_content(url) log.debug("toggle_watched item info: {0}".format(result)) user_data = result.get("UserData", None) if user_data is None: return if user_data.get("Played", False) is False: mark_item_watched(item_id) else: mark_item_unwatched(item_id) def mark_item_watched(item_id): log.debug("Mark Item Watched: {0}".format(item_id)) url = "{server}/Users/{userid}/PlayedItems/" + item_id downloadUtils.download_url(url, post_body="", method="POST") 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") xbmc.executebuiltin("Container.Refresh") def mark_item_unwatched(item_id): log.debug("Mark Item UnWatched: {0}".format(item_id)) url = "{server}/Users/{userid}/PlayedItems/" + item_id downloadUtils.download_url(url, method="DELETE") 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") xbmc.executebuiltin("Container.Refresh") def mark_item_favorite(item_id): log.debug("Add item to favourites: {0}".format(item_id)) url = "{server}/Users/{userid}/FavoriteItems/" + item_id downloadUtils.download_url(url, post_body="", method="POST") 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") xbmc.executebuiltin("Container.Refresh") def unmark_item_favorite(item_id): log.debug("Remove item from favourites: {0}".format(item_id)) url = "{server}/Users/{userid}/FavoriteItems/" + item_id downloadUtils.download_url(url, method="DELETE") 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") xbmc.executebuiltin("Container.Refresh") def delete(item_id): item = downloadUtils.download_url("{server}/Users/{userid}/Items/" + item_id + "?format=json") item_id = item.get("Id") item_name = item.get("Name", "") series_name = item.get("SeriesName", "") ep_number = item.get("IndexNumber", -1) final_name = "" if series_name: final_name += series_name + " - " if ep_number != -1: final_name += "Episode %02d - " % (ep_number,) final_name += item_name if not item.get("CanDelete", False): xbmcgui.Dialog().ok(string_load(30135), string_load(30417), final_name) return return_value = xbmcgui.Dialog().yesno(string_load(30091), '{}\n{}'.format(final_name, string_load(30092))) if return_value: log.debug('Deleting Item: {0}'.format(item_id)) url = '{server}/Items/' + item_id progress = xbmcgui.DialogProgress() progress.create(string_load(30052), string_load(30053)) downloadUtils.download_url(url, method="DELETE") progress.close() 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") xbmc.executebuiltin("Container.Refresh") def get_params(): ''' Retrieve the request data from Kodi ''' plugin_path = sys.argv[0] paramstring = sys.argv[2] log.debug("Parameter string: {0}".format(paramstring)) log.debug("Plugin Path string: {0}".format(plugin_path)) param = dict(parse_qsl(paramstring[1:])) # add plugin path request_path = plugin_path.replace("plugin://plugin.video.jellycon", "") param["request_path"] = request_path log.debug("JellyCon -> Detected parameters: {0}".format(param)) return param def show_menu(params): log.debug("showMenu(): {0}".format(params)) home_window = HomeWindow() settings = xbmcaddon.Addon() item_id = params["item_id"] url = "{server}/Users/{userid}/Items/" + item_id + "?format=json" data_manager = DataManager() result = data_manager.get_content(url) log.debug("Menu item info: {0}".format(result)) if result is None: return action_items = [] if result["Type"] in ["Episode", "Movie", "Music", "Video", "Audio", "TvChannel", "Program"]: li = xbmcgui.ListItem(string_load(30314)) li.setProperty('menu_id', 'play') action_items.append(li) if result["Type"] in ["Season", "MusicAlbum", "Playlist"]: li = xbmcgui.ListItem(string_load(30317)) li.setProperty('menu_id', 'play_all') action_items.append(li) if result["Type"] in ["Episode", "Movie", "Video", "TvChannel", "Program"]: li = xbmcgui.ListItem(string_load(30275)) li.setProperty('menu_id', 'transcode') action_items.append(li) if result["Type"] in ["Episode", "Movie", "Music", "Video", "Audio"]: li = xbmcgui.ListItem(string_load(30402)) li.setProperty('menu_id', 'add_to_playlist') action_items.append(li) if result["Type"] in ("Movie", "Series"): li = xbmcgui.ListItem(string_load(30307)) li.setProperty('menu_id', 'play_trailer') action_items.append(li) if result["Type"] == "Episode" and result["ParentId"] is not None: li = xbmcgui.ListItem(string_load(30327)) li.setProperty('menu_id', 'view_season') action_items.append(li) if result["Type"] in ("Series", "Season", "Episode"): li = xbmcgui.ListItem(string_load(30354)) li.setProperty('menu_id', 'view_series') action_items.append(li) if result["Type"] == "Movie": li = xbmcgui.ListItem("Show Extras") li.setProperty('menu_id', 'show_extras') action_items.append(li) user_data = result.get("UserData", None) if user_data: progress = user_data.get("PlaybackPositionTicks", 0) != 0 played = user_data.get("Played", False) if not played or progress: li = xbmcgui.ListItem(string_load(30270)) li.setProperty('menu_id', 'mark_watched') action_items.append(li) if played or progress: li = xbmcgui.ListItem(string_load(30271)) li.setProperty('menu_id', 'mark_unwatched') action_items.append(li) if user_data.get("IsFavorite", False) is False: li = xbmcgui.ListItem(string_load(30272)) li.setProperty('menu_id', 'jellyfin_set_favorite') action_items.append(li) else: li = xbmcgui.ListItem(string_load(30273)) li.setProperty('menu_id', 'jellyfin_unset_favorite') action_items.append(li) can_delete = result.get("CanDelete", False) if can_delete: li = xbmcgui.ListItem(string_load(30274)) li.setProperty('menu_id', 'delete') action_items.append(li) safe_delete = home_window.get_property("safe_delete_plugin_available") == "true" if safe_delete: li = xbmcgui.ListItem("Safe Delete") li.setProperty('menu_id', 'safe_delete') action_items.append(li) li = xbmcgui.ListItem(string_load(30398)) li.setProperty('menu_id', 'refresh_server') action_items.append(li) li = xbmcgui.ListItem(string_load(30281)) li.setProperty('menu_id', 'refresh_images') action_items.append(li) if result["Type"] in ["Movie", "Series"]: li = xbmcgui.ListItem(string_load(30399)) li.setProperty('menu_id', 'hide') action_items.append(li) li = xbmcgui.ListItem(string_load(30401)) li.setProperty('menu_id', 'info') action_items.append(li) window = xbmcgui.Window(xbmcgui.getCurrentWindowId()) container_view_id = str(window.getFocusId()) container_content_type = xbmc.getInfoLabel("Container.Content") view_key = "view-" + 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)) if container_content_type in ["movies", "tvshows", "seasons", "episodes", "sets"]: if view_match: li = xbmcgui.ListItem("Unset as default view") li.setProperty('menu_id', 'unset_view') action_items.append(li) else: li = xbmcgui.ListItem("Set as default view") li.setProperty('menu_id', 'set_view') 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: {0}".format(selected_action)) del action_menu if selected_action == "play": log.debug("Play Item") play_action(params) elif selected_action == "set_view": 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)) settings.setSetting(view_key, "") elif selected_action == "refresh_server": url = ("{server}/Items/" + item_id + "/Refresh" + "?Recursive=true" + "&ImageRefreshMode=FullRefresh" + "&MetadataRefreshMode=FullRefresh" + "&ReplaceAllImages=true" + "&ReplaceAllMetadata=true") res = downloadUtils.download_url(url, post_body="", method="POST") log.debug("Refresh Server Responce: {0}".format(res)) elif selected_action == "hide": user_details = load_user_details(settings) user_name = user_details["username"] hide_tag_string = "hide-" + user_name url = "{server}/Items/" + item_id + "/Tags/Add" post_tag_data = {"Tags": [{"Name": hide_tag_string}]} res = downloadUtils.download_url(url, post_body=post_tag_data, method="POST") log.debug("Add Tag Responce: {0}".format(res)) check_for_new_content() 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") xbmc.executebuiltin("Container.Refresh") elif selected_action == "play_all": play_action(params) elif selected_action == "play_trailer": play_item_trailer(item_id) 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") 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)) if selected_transcode_value > 0: settings.setSetting("force_max_stream_bitrate", str(selected_transcode_value)) play_action(params) elif selected_action == "add_to_playlist": params["action"] = "add_to_playlist" play_action(params) elif selected_action == "jellyfin_set_favorite": mark_item_favorite(item_id) elif selected_action == "jellyfin_unset_favorite": unmark_item_favorite(item_id) elif selected_action == "mark_watched": mark_item_watched(item_id) elif selected_action == "mark_unwatched": mark_item_unwatched(item_id) elif selected_action == "delete": delete(item_id) elif selected_action == "safe_delete": url = "{server}/jellyfin_safe_delete/delete_item/" + item_id result = downloadUtils.download_url(url) dialog = xbmcgui.Dialog() if result: log.debug("Safe_Delete_Action: {0}".format(result)) action_token = result["action_token"] message = "You are about to delete the following item[CR][CR]" message += "Type: " + result["item_info"]["Item_type"] + "[CR]" if result["item_info"]["Item_type"] == "Series": message += "Name: " + result["item_info"]["item_name"] + "[CR]" elif result["item_info"]["Item_type"] == "Season": message += "Season: " + str(result["item_info"]["season_number"]) + "[CR]" message += "Name: " + result["item_info"]["season_name"] + "[CR]" elif result["item_info"]["Item_type"] == "Episode": message += "Series: " + result["item_info"]["series_name"] + "[CR]" message += "Season: " + result["item_info"]["season_name"] + "[CR]" message += "Episode: " + str(result["item_info"]["episode_number"]) + "[CR]" message += "Name: " + result["item_info"]["item_name"] + "[CR]" else: message += "Name: " + result["item_info"]["item_name"] + "[CR]" message += "[CR]File List[CR][CR]" for file_info in result["file_list"]: message += " - " + file_info["Key"] + " (" + convert_size(file_info["Value"]) + ")[CR]" message += "[CR][CR]Are you sure?[CR][CR]" confirm_dialog = SafeDeleteDialog("SafeDeleteDialog.xml", PLUGINPATH, "default", "720p") confirm_dialog.message = message confirm_dialog.heading = "Confirm delete files?" confirm_dialog.doModal() log.debug("safe_delete_confirm_dialog: {0}".format(confirm_dialog.confirm)) if confirm_dialog.confirm: url = "{server}/jellyfin_safe_delete/delete_item_action" playback_info = { 'item_id': item_id, 'action_token': action_token } delete_action = downloadUtils.download_url(url, method="POST", post_body=playback_info) log.debug("Delete result action: {0}".format(delete_action)) if not delete_action: dialog.ok("Error", "Error deleting files", "Error in responce from server") elif not delete_action.get("result"): dialog.ok("Error", "Error deleting files", delete_action["message"]) else: dialog.ok("Deleted", "Files deleted") else: dialog.ok("Error", "Error getting safe delete confirmation") elif selected_action == "show_extras": u = "{server}/Users/{userid}/Items/" + item_id + "/SpecialFeatures" action_url = ("plugin://plugin.video.jellycon/?url=" + quote(u) + "&mode=GET_CONTENT&media_type=Videos") built_in_command = 'ActivateWindow(Videos, ' + action_url + ', return)' 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 = ('{server}/Shows/' + series_id + '/Episodes' '?userId={userid}' + '&seasonId=' + parent_id + '&IsVirtualUnAired=false' + '&IsMissing=false' + '&Fields=SpecialEpisodeNumbers,{field_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)' xbmc.executebuiltin(built_in_command) elif selected_action == "view_series": xbmc.executebuiltin("Dialog.Close(all,true)") series_id = result["SeriesId"] if not series_id: series_id = item_id u = ('{server}/Shows/' + series_id + '/Seasons' '?userId={userid}' + '&Fields={field_filters}' + '&format=json') action_url = ("plugin://plugin.video.jellycon/?url=" + quote(u) + "&mode=GET_CONTENT&media_type=Series") if xbmc.getCondVisibility("Window.IsActive(home)"): built_in_command = 'ActivateWindow(Videos, ' + action_url + ', return)' else: built_in_command = 'Container.Update(' + action_url + ')' xbmc.executebuiltin(built_in_command) elif selected_action == "refresh_images": CacheArtwork().delete_cached_images(item_id) elif selected_action == "info": xbmc.executebuiltin("Dialog.Close(all,true)") xbmc.executebuiltin("Action(info)") def populate_listitem(item_id): log.debug("populate_listitem: {0}".format(item_id)) url = "{server}/Users/{userid}/Items/" + item_id + "?format=json" result = downloadUtils.download_url(url) log.debug("populate_listitem item info: {0}".format(result)) item_title = result.get("Name", string_load(30280)) list_item = xbmcgui.ListItem(label=item_title) server = downloadUtils.get_server() art = get_art(result, server=server) list_item.setIconImage(art['thumb']) # back compat list_item.setProperty('fanart_image', art['fanart']) # back compat list_item.setProperty('discart', art['discart']) # not avail to setArt list_item.setArt(art) list_item.setProperty('IsPlayable', 'false') list_item.setProperty('IsFolder', 'false') list_item.setProperty('id', result.get("Id")) # play info details = { 'title': item_title, 'plot': result.get("Overview") } list_item.setInfo("Video", infoLabels=details) return list_item def show_content(params): log.debug("showContent Called: {0}".format(params)) item_type = params.get("item_type") settings = xbmcaddon.Addon() group_movies = settings.getSetting('group_movies') == "true" if item_type.lower().find("movie") == -1: group_movies = False content_url = ("{server}/Users/{userid}/Items" + "?format=json" + "&ImageTypeLimit=1" + "&IsMissing=False" + "&Fields={field_filters}" + '&CollapseBoxSetItems=' + str(group_movies) + '&GroupItemsIntoCollections=' + str(group_movies) + "&Recursive=true" + '&SortBy=Name' + '&SortOrder=Ascending' + "&IsVirtualUnaired=false" + "&IncludeItemTypes=" + item_type) log.debug("showContent Content Url: {0}".format(content_url)) get_content(content_url, params) def search_results_person(params): handle = int(sys.argv[1]) person_id = params.get("person_id") details_url = ('{server}/Users/{userid}/items' + '?PersonIds=' + person_id + '&Recursive=true' + '&Fields={field_filters}' + '&format=json') params["name_format"] = "Episode|episode_name_format" 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)) if detected_type is not None: # if the media type is not set then try to use the detected type log.debug("Detected content type: {0}".format(detected_type)) content_type = None if detected_type == "Movie": content_type = 'movies' elif detected_type == "Episode": content_type = 'episodes' elif detected_type == "Series": content_type = 'tvshows' elif detected_type == "Music" or detected_type == "Audio" or detected_type == "Musicalbum": content_type = 'songs' if content_type: xbmcplugin.setContent(handle, content_type) if dir_items is not None: xbmcplugin.addDirectoryItems(handle, dir_items) xbmcplugin.endOfDirectory(handle, cacheToDisc=False) def search_results(params): item_type = params.get('item_type') query_string = params.get('query') if query_string: log.debug("query_string : {0}".format(query_string)) query_string = unquote(query_string) log.debug("query_string : {0}".format(query_string)) item_type = item_type.lower() if item_type == 'movie': heading_type = string_load(30231) content_type = 'movies' elif item_type == 'series': heading_type = string_load(30229) content_type = 'tvshows' elif item_type == 'episode': heading_type = string_load(30235) content_type = 'episodes' params["name_format"] = "Episode|episode_name_format" elif item_type == "music" or item_type == "audio" or item_type == "musicalbum": heading_type = 'Music' content_type = 'songs' elif item_type == "person": heading_type = 'Artists' content_type = 'artists' else: heading_type = item_type content_type = 'video' handle = int(sys.argv[1]) if not query_string: home_window = HomeWindow() last_search = home_window.get_property("last_search") kb = xbmc.Keyboard() kb.setHeading(heading_type.capitalize() + ' ' + string_load(30246).lower()) kb.setDefault(last_search) kb.doModal() if kb.isConfirmed(): user_input = kb.getText().strip() else: return home_window.set_property("last_search", user_input) log.debug('searchResults Called: {0}'.format(params)) query = user_input else: query = query_string query = quote(query) log.debug("query : {0}".format(query)) if (not item_type) or (not query): return # show a progress indicator if needed settings = xbmcaddon.Addon() progress = None if settings.getSetting('showLoadProgress') == "true": progress = xbmcgui.DialogProgress() progress.create(string_load(30112)) progress.update(0, string_load(30113)) # what type of search if item_type == "person": search_url = ("{server}/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={userid}") person_search_results = dataManager.get_content(search_url) log.debug("Person Search Result : {0}".format(person_search_results)) if person_search_results is None: return person_items = person_search_results.get("Items", []) server = downloadUtils.get_server() list_items = [] for item in person_items: person_id = item.get('Id') person_name = item.get('Name') person_thumbnail = downloadUtils.get_artwork(item, "Primary", server=server) action_url = sys.argv[0] + "?mode=NEW_SEARCH_PERSON&person_id=" + person_id list_item = xbmcgui.ListItem(label=person_name) list_item.setProperty("id", person_id) art_links = {} art_links["icon"] = "DefaultActor.png" if person_thumbnail: art_links["thumb"] = person_thumbnail art_links["poster"] = person_thumbnail list_item.setArt(art_links) item_tupple = (action_url, list_item, True) list_items.append(item_tupple) xbmcplugin.setContent(handle, 'artists') xbmcplugin.addDirectoryItems(handle, list_items) xbmcplugin.endOfDirectory(handle, cacheToDisc=False) else: search_url = ("{server}/Users/{userid}/Items" + "?searchTerm=" + query + "&IncludePeople=false" + "&IncludeMedia=true" + "&IncludeGenres=false" + "&IncludeStudios=false" + "&IncludeArtists=false" + "&IncludeItemTypes=" + item_type + "&Limit=16" + "&Fields={field_filters}" + "&Recursive=true" + "&EnableTotalRecordCount=false" + "&ImageTypeLimit=1") # set content type xbmcplugin.setContent(handle, content_type) dir_items, detected_type, total_records = process_directory(search_url, progress, params) xbmcplugin.addDirectoryItems(handle, dir_items) xbmcplugin.endOfDirectory(handle, cacheToDisc=False) if progress is not None: progress.update(100, string_load(30125)) progress.close() def play_action(params): log.debug("== ENTER: PLAY ==") log.debug("PLAY ACTION PARAMS: {0}".format(params)) item_id = params.get("item_id") auto_resume = params.get("auto_resume", "-1") if auto_resume == 'None': auto_resume = '-1' if auto_resume: auto_resume = int(auto_resume) else: auto_resume = -1 log.debug("AUTO_RESUME: {0}".format(auto_resume)) force_transcode = params.get("force_transcode", None) is not None log.debug("FORCE_TRANSCODE: {0}".format(force_transcode)) media_source_id = params.get("media_source_id", "") log.debug("media_source_id: {0}".format(media_source_id)) subtitle_stream_index = params.get("subtitle_stream_index") log.debug("subtitle_stream_index: {0}".format(subtitle_stream_index)) audio_stream_index = params.get("audio_stream_index") log.debug("audio_stream_index: {0}".format(audio_stream_index)) action = params.get("action", "play") # set the current playing item id # set all the playback info, this will be picked up by the service # the service will then start the playback xbmc.Player().stop() play_info = {} play_info["action"] = action play_info["item_id"] = item_id play_info["auto_resume"] = str(auto_resume) play_info["force_transcode"] = force_transcode play_info["media_source_id"] = media_source_id play_info["subtitle_stream_index"] = subtitle_stream_index play_info["audio_stream_index"] = audio_stream_index log.info("Sending jellycon_play_action : {0}".format(play_info)) play_file(play_info) def play_item_trailer(item_id): log.debug("== ENTER: playTrailer ==") url = ("{server}/Users/{userid}/Items/%s/LocalTrailers?format=json" % item_id) result = downloadUtils.download_url(url) if result is None: return log.debug("LocalTrailers {0}".format(result)) count = 1 trailer_names = [] trailer_list = [] for trailer in result: info = {} info["type"] = "local" name = trailer.get("Name") while not name or name in trailer_names: name = "Trailer " + str(count) count += 1 info["name"] = name info["id"] = trailer.get("Id") count += 1 trailer_names.append(name) trailer_list.append(info) url = ("{server}/Users/{userid}/Items/%s?format=json&Fields=RemoteTrailers" % item_id) result = downloadUtils.download_url(url) log.debug("RemoteTrailers: {0}".format(result)) count = 1 if result is None: return remote_trailers = result.get("RemoteTrailers", []) for trailer in remote_trailers: info = {} info["type"] = "remote" url = trailer.get("Url", "none") if url.lower().find("youtube") != -1: info["url"] = url name = trailer.get("Name") while not name or name in trailer_names: name = "Trailer " + str(count) count += 1 info["name"] = name trailer_names.append(name) trailer_list.append(info) log.debug("TrailerList: {0}".format(trailer_list)) trailer_text = [] for trailer in trailer_list: name = trailer.get("name") + " (" + trailer.get("type") + ")" trailer_text.append(name) dialog = xbmcgui.Dialog() resp = dialog.select(string_load(30308), trailer_text) if resp > -1: trailer = trailer_list[resp] log.debug("SelectedTrailer: {0}".format(trailer)) if trailer.get("type") == "local": params = {} params["item_id"] = trailer.get("id") play_action(params) 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)) xbmc.executebuiltin(youtube_plugin)