diff options
Diffstat (limited to 'plugin.video.embycon/service.py')
-rw-r--r-- | plugin.video.embycon/service.py | 328 |
1 files changed, 46 insertions, 282 deletions
diff --git a/plugin.video.embycon/service.py b/plugin.video.embycon/service.py index 60b1575..71b5320 100644 --- a/plugin.video.embycon/service.py +++ b/plugin.video.embycon/service.py @@ -1,19 +1,21 @@ # coding=utf-8 # Gnu General Public License - see LICENSE.TXT -import xbmc -import xbmcaddon -import xbmcgui import time import json import traceback +import binascii + +import xbmc +import xbmcaddon +import xbmcgui from resources.lib.downloadutils import DownloadUtils from resources.lib.simple_logging import SimpleLogging -from resources.lib.play_utils import playFile +from resources.lib.play_utils import Service, PlaybackService, sendProgress from resources.lib.kodi_utils import HomeWindow -from resources.lib.translation import i18n from resources.lib.widgets import checkForNewContent +from resources.lib.websocket_client import WebSocketClient # clear user and token when logging in home_window = HomeWindow() @@ -28,282 +30,46 @@ download_utils = DownloadUtils() try: download_utils.authenticate() except Exception as error: - log.error("Error with initial service auth: " + str(error)) - - -def hasData(data): - if data is None or len(data) == 0 or data == "None": - return False - else: - return True - - -def sendProgress(): - playing_file = xbmc.Player().getPlayingFile() - play_data = monitor.played_information.get(playing_file) - - if play_data is None: - return - - log.debug("Sending Progress Update") - - play_time = xbmc.Player().getTime() - play_data["currentPossition"] = play_time - - item_id = play_data.get("item_id") - if item_id is None: - return - - ticks = int(play_time * 10000000) - paused = play_data.get("paused", False) - playback_type = play_data.get("playback_type") - play_session_id = play_data.get("play_session_id") - - postdata = { - 'QueueableMediaTypes': "Video", - 'CanSeek': True, - 'ItemId': item_id, - 'MediaSourceId': item_id, - 'PositionTicks': ticks, - 'IsPaused': paused, - 'IsMuted': False, - 'PlayMethod': playback_type, - 'PlaySessionId': play_session_id - } - - log.debug("Sending POST progress started: %s." % postdata) - - url = "{server}/emby/Sessions/Playing/Progress" - download_utils.downloadUrl(url, postBody=postdata, method="POST") - -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')) - - # everything is off so return - if prompt_next_percentage == 100 and prompt_delete_episode_percentage == 100 and prompt_delete_movie_percentage == 100: - return - - jsonData = download_utils.downloadUrl("{server}/emby/Users/{userid}/Items/" + - item_id + "?format=json", - suppress=False, popup=1) - result = json.loads(jsonData) - prompt_to_delete = False - runtime = result.get("RunTimeTicks", 0) - - # if no runtime we cant calculate perceantge so just return - if runtime == 0: - log.debug("No runtime so returing") - return - - # item percentage complete - percenatge_complete = int(((current_possition * 10000000) / runtime) * 100) - log.debug("Episode Percentage Complete: %s" % percenatge_complete) - - if (prompt_delete_episode_percentage < 100 and - result.get("Type", "na") == "Episode" and - percenatge_complete > prompt_delete_episode_percentage): - prompt_to_delete = True - - if (prompt_delete_movie_percentage < 100 and - result.get("Type", "na") == "Movie" and - percenatge_complete > prompt_delete_movie_percentage): - prompt_to_delete = True - - if prompt_to_delete: - log.debug("Prompting for delete") - resp = xbmcgui.Dialog().yesno(i18n('confirm_file_delete'), i18n('file_delete_confirm'), autoclose=10000) - if resp: - log.debug("Deleting item: %s" % item_id) - url = "{server}/emby/Items/%s?format=json" % item_id - download_utils.downloadUrl(url, method="DELETE") - xbmc.executebuiltin("Container.Refresh") - - # prompt for next episode - if (prompt_next_percentage < 100 and - result.get("Type", "na") == "Episode" and - percenatge_complete > prompt_next_percentage): - parendId = result.get("ParentId", "na") - item_index = result.get("IndexNumber", -1) - - if parendId == "na": - log.debug("No parent id, can not prompt for next episode") - return - - if item_index == -1: - log.debug("No episode number, can not prompt for next episode") - return - - jsonData = download_utils.downloadUrl('{server}/emby/Users/{userid}/Items?' + - '?Recursive=true' + - '&ParentId=' + parendId + - #'&Filters=IsUnplayed,IsNotFolder' + - '&IsVirtualUnaired=false' + - '&IsMissing=False' + - '&IncludeItemTypes=Episode' + - '&ImageTypeLimit=1' + - '&format=json', - suppress=False, popup=1) - - items_result = json.loads(jsonData) - log.debug("Prompt Next Item Details: %s" % items_result) - # find next episode - item_list = items_result.get("Items", []) - for item in item_list: - index = item.get("IndexNumber", -1) - 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) + log.error("Error with initial service auth: {0}", error) - if resp: - next_item_id = item.get("Id") - log.debug("Playing Next Episode: %s" % next_item_id) - - play_info = {} - play_info["item_id"] = next_item_id - play_info["auto_resume"] = "-1" - play_info["force_transcode"] = False - play_data = json.dumps(play_info) - - home_window = HomeWindow() - home_window.setProperty("item_id", next_item_id) - home_window.setProperty("play_item_message", play_data) - - break - - -def stopAll(played_information): - if len(played_information) == 0: - return - - log.debug("played_information : " + str(played_information)) - - for item_url in played_information: - data = played_information.get(item_url) - if data is not None: - log.debug("item_url : " + item_url) - log.debug("item_data : " + str(data)) - - current_possition = data.get("currentPossition", 0) - emby_item_id = data.get("item_id") - - if hasData(emby_item_id): - log.debug("Playback Stopped at: " + str(int(current_possition * 10000000))) - - url = "{server}/emby/Sessions/Playing/Stopped" - postdata = { - 'ItemId': emby_item_id, - 'MediaSourceId': emby_item_id, - 'PositionTicks': int(current_possition * 10000000) - } - download_utils.downloadUrl(url, postBody=postdata, method="POST") - - promptForStopActions(emby_item_id, current_possition) - - played_information.clear() - - -class Service(xbmc.Player): - played_information = {} - - def __init__(self, *args): - log.debug("Starting monitor service: " + str(args)) - self.played_information = {} - - def onPlayBackStarted(self): - # Will be called when xbmc starts playing a file - stopAll(self.played_information) - - current_playing_file = xbmc.Player().getPlayingFile() - log.debug("onPlayBackStarted: " + current_playing_file) - - home_window = HomeWindow() - emby_item_id = home_window.getProperty("item_id") - playback_type = home_window.getProperty("PlaybackType_" + emby_item_id) - play_session_id = home_window.getProperty("PlaySessionId_" + emby_item_id) - - # if we could not find the ID of the current item then return - if emby_item_id is None or len(emby_item_id) == 0: - return - - log.debug("Sending Playback Started") - postdata = { - 'QueueableMediaTypes': "Video", - 'CanSeek': True, - 'ItemId': emby_item_id, - 'MediaSourceId': emby_item_id, - 'PlayMethod': playback_type, - 'PlaySessionId': play_session_id - } - - log.debug("Sending POST play started: %s." % postdata) - - url = "{server}/emby/Sessions/Playing" - download_utils.downloadUrl(url, postBody=postdata, method="POST") - - data = {} - data["item_id"] = emby_item_id - data["paused"] = False - data["playback_type"] = playback_type - data["play_session_id"] = play_session_id - self.played_information[current_playing_file] = data - - log.debug("ADDING_FILE : " + current_playing_file) - log.debug("ADDING_FILE : " + str(self.played_information)) +# set up all the services +monitor = Service() +playback_service = PlaybackService(monitor) - def onPlayBackEnded(self): - # Will be called when kodi stops playing a file - log.debug("EmbyCon Service -> onPlayBackEnded") - home_window = HomeWindow() - home_window.clearProperty("item_id") - stopAll(self.played_information) +home_window = HomeWindow() +last_progress_update = time.time() +last_content_check = time.time() +websocket_client = WebSocketClient() - def onPlayBackStopped(self): - # Will be called when user stops kodi playing a file - log.debug("onPlayBackStopped") - home_window = HomeWindow() - home_window.clearProperty("item_id") - stopAll(self.played_information) +# start the WebSocket Client running +settings = xbmcaddon.Addon(id='plugin.video.embycon') +remote_control = settings.getSetting('remoteControl') == "true" +if remote_control: + websocket_client.start() - def onPlayBackPaused(self): - # Will be called when kodi pauses the video - log.debug("onPlayBackPaused") - current_file = xbmc.Player().getPlayingFile() - play_data = monitor.played_information.get(current_file) - if play_data is not None: - play_data['paused'] = True - sendProgress() +def get_now_playing(): - def onPlayBackResumed(self): - # Will be called when kodi resumes the video - log.debug("onPlayBackResumed") - current_file = xbmc.Player().getPlayingFile() - play_data = monitor.played_information.get(current_file) + # Get the active player + result = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "id": 1, "method": "Player.GetActivePlayers"}') + result = unicode(result, 'utf-8', errors='ignore') + log.debug("Got active player: {0}", result) + result = json.loads(result) - if play_data is not None: - play_data['paused'] = False - sendProgress() + if 'result' in result and len(result["result"]) > 0: + playerid = result["result"][0]["playerid"] - def onPlayBackSeek(self, time, seekOffset): - # Will be called when kodi seeks in video - log.debug("onPlayBackSeek") - sendProgress() + # Get details of the playing media + log.debug("Getting details of now playing media") + result = xbmc.executeJSONRPC( + '{"jsonrpc": "2.0", "id": 1, "method": "Player.GetItem", "params": {"playerid": ' + str( + playerid) + ', "properties": ["showtitle", "tvshowid", "episode", "season", "playcount", "genre", "plotoutline", "uniqueid"] } }') + result = unicode(result, 'utf-8', errors='ignore') + log.debug("playing_item_details: {0}", result) + result = json.loads(result) + return result -monitor = Service() -home_window = HomeWindow() -last_progress_update = time.time() -last_content_check = time.time() # 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. @@ -316,29 +82,27 @@ while not xbmc.abortRequested: # if playing every 10 seconds updated the server with progress if (time.time() - last_progress_update) > 10: last_progress_update = time.time() - sendProgress() + sendProgress(monitor) 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() + #get_now_playing() + except Exception as error: - log.error("Exception in Playback Monitor : " + str(error)) - log.error(traceback.format_exc()) + log.error("Exception in Playback Monitor: {0}", error) + log.error("{0}", traceback.format_exc()) xbmc.sleep(1000) +# stop the WebSocket Client +websocket_client.stop_client() + # clear user and token when loggin off home_window.clearProperty("userid") home_window.clearProperty("AccessToken") home_window.clearProperty("Params") -log.error("Service shutting down") +log.debug("Service shutting down") |