summaryrefslogtreecommitdiff
path: root/plugin.video.embycon/resources/lib/play_utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'plugin.video.embycon/resources/lib/play_utils.py')
-rw-r--r--plugin.video.embycon/resources/lib/play_utils.py687
1 files changed, 588 insertions, 99 deletions
diff --git a/plugin.video.embycon/resources/lib/play_utils.py b/plugin.video.embycon/resources/lib/play_utils.py
index e6455c5..16146d9 100644
--- a/plugin.video.embycon/resources/lib/play_utils.py
+++ b/plugin.video.embycon/resources/lib/play_utils.py
@@ -1,5 +1,7 @@
# Gnu General Public License - see LICENSE.TXT
+import binascii
+
import xbmc
import xbmcgui
import xbmcaddon
@@ -9,42 +11,175 @@ import time
import json
import hashlib
+from resources.lib.error import catch_except
from simple_logging import SimpleLogging
from downloadutils import DownloadUtils
from resume_dialog import ResumeDialog
-from utils import PlayUtils, getArt, id_generator
+from utils import PlayUtils, getArt, id_generator, send_event_notification
from kodi_utils import HomeWindow
from translation import i18n
from json_rpc import json_rpc
+from datamanager import DataManager
+from item_functions import get_next_episode, extract_item_info
log = SimpleLogging(__name__)
-downloadUtils = DownloadUtils()
+download_utils = DownloadUtils()
+
+@catch_except()
+def playAllFiles(id, monitor):
+ log.debug("PlayAllFiles for parent item id: {0}", id)
+
+ url = ('{server}/emby/Users/{userid}/items' +
+ '?ParentId=' + id +
+ '&Fields=MediaSources' +
+ '&format=json')
+ data_manager = DataManager()
+ result = data_manager.GetContent(url)
+ log.debug("PlayAllFiles items info: {0}", result)
+
+ # process each item
+ items = result["Items"]
+ if items is None:
+ items = []
+
+ settings = xbmcaddon.Addon('plugin.video.embycon')
+ server = download_utils.getServer()
+
+ playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
+ playlist.clear()
+ for item in items:
-def playFile(play_info):
+ item_id = item.get("Id")
+ sources = item.get("MediaSources")
+ selected_media_source = sources[0]
+
+ listitem_props = []
+ playback_type = "0"
+ playurl = None
+ play_session_id = id_generator()
+ log.debug("play_session_id: {0}", play_session_id)
+
+ # check if strm file, path will contain contain strm contents
+ if selected_media_source.get('Container') == 'strm':
+ playurl, listitem_props = PlayUtils().getStrmDetails(selected_media_source)
+ if playurl is None:
+ return
+
+ if not playurl:
+ playurl, playback_type = PlayUtils().getPlayUrl(item_id, selected_media_source, False, play_session_id)
+
+ log.debug("Play URL: {0} ListItem Properties: {1}", playurl, listitem_props)
+
+ playback_type_string = "DirectPlay"
+ if playback_type == "2":
+ playback_type_string = "Transcode"
+ elif playback_type == "1":
+ playback_type_string = "DirectStream"
+
+ # add the playback type into the overview
+ if item.get("Overview", None) is not None:
+ item["Overview"] = playback_type_string + "\n" + item.get("Overview")
+ else:
+ item["Overview"] = playback_type_string
+
+ # add title decoration is needed
+ item_title = item.get("Name", i18n('missing_title'))
+ list_item = xbmcgui.ListItem(label=item_title)
+
+ # add playurl and data to the monitor
+ data = {}
+ data["item_id"] = item_id
+ data["playback_type"] = playback_type_string
+ data["play_session_id"] = play_session_id
+ data["play_action_type"] = "play_all"
+ monitor.played_information[playurl] = data
+ log.debug("Add to played_information: {0}", monitor.played_information)
+
+ list_item.setPath(playurl)
+ list_item = setListItemProps(item_id, list_item, item, server, listitem_props, item_title)
+
+ playlist.add(playurl, list_item)
+
+ xbmc.Player().play(playlist)
+
+
+def playFile(play_info, monitor):
id = play_info.get("item_id")
- auto_resume = play_info.get("auto_resume")
- force_transcode = play_info.get("force_transcode")
+ auto_resume = play_info.get("auto_resume", "-1")
+ force_transcode = play_info.get("force_transcode", False)
+ media_source_id = play_info.get("media_source_id", "")
+ use_default = play_info.get("use_default", False)
- log.debug("playFile id(%s) resume(%s) force_transcode(%s)" % (id, auto_resume, force_transcode))
+ log.debug("playFile id({0}) resume({1}) force_transcode({2})", id, auto_resume, force_transcode)
settings = xbmcaddon.Addon('plugin.video.embycon')
addon_path = settings.getAddonInfo('path')
+ force_auto_resume = settings.getSetting('forceAutoResume') == 'true'
jump_back_amount = int(settings.getSetting("jump_back_amount"))
- server = downloadUtils.getServer()
+ server = download_utils.getServer()
- jsonData = downloadUtils.downloadUrl("{server}/emby/Users/{userid}/Items/" + id + "?format=json",
- suppress=False, popup=1)
- result = json.loads(jsonData)
- log.debug("Playfile item info: " + str(result))
+ url = "{server}/emby/Users/{userid}/Items/" + id + "?format=json"
+ data_manager = DataManager()
+ result = data_manager.GetContent(url)
+ log.debug("Playfile item info: {0}", result)
+
+ if result is None:
+ log.debug("Playfile item was None, so can not play!")
+ return
+
+ # if this is a season, tv show or album then play all items
+ if result.get("Type") == "Season" or result.get("Type") == "MusicAlbum":
+ return playAllFiles(id, monitor)
+
+ # select the media source to use
+ media_sources = result.get('MediaSources')
+ selected_media_source = None
+
+ if media_sources is None or len(media_sources) == 0:
+ log.debug("Play Failed! There is no MediaSources data!")
+ return
+
+ elif len(media_sources) == 1:
+ selected_media_source = media_sources[0]
+
+ elif media_source_id != "":
+ for source in media_sources:
+ if source.get("Id", "na") == media_source_id:
+ selected_media_source = source
+ break
+
+ elif len(media_sources) > 1:
+ sourceNames = []
+ for source in media_sources:
+ sourceNames.append(source.get("Name", "na"))
+
+ dialog = xbmcgui.Dialog()
+ resp = dialog.select(i18n('select_source'), sourceNames)
+ if resp > -1:
+ selected_media_source = media_sources[resp]
+ else:
+ log.debug("Play Aborted, user did not select a MediaSource")
+ return
+
+ if selected_media_source is None:
+ log.debug("Play Aborted, MediaSource was None")
+ return
seekTime = 0
auto_resume = int(auto_resume)
+ # process user data for resume points
if auto_resume != -1:
seekTime = (auto_resume / 1000) / 10000
+
+ elif force_auto_resume:
+ userData = result.get("UserData")
+ reasonableTicks = int(userData.get("PlaybackPositionTicks")) / 1000
+ seekTime = reasonableTicks / 10000
+
else:
userData = result.get("UserData")
if userData.get("PlaybackPositionTicks") != 0:
@@ -58,13 +193,13 @@ def playFile(play_info):
resumeDialog.doModal()
resume_result = resumeDialog.getResumeAction()
del resumeDialog
- log.debug("Resume Dialog Result: " + str(resume_result))
+ log.debug("Resume Dialog Result: {0}", resume_result)
# check system settings for play action
# if prompt is set ask to set it to auto resume
params = {"setting": "myvideos.selectaction"}
setting_result = json_rpc('Settings.getSettingValue').execute(params)
- log.debug("Current Setting (myvideos.selectaction): %s" % setting_result)
+ log.debug("Current Setting (myvideos.selectaction): {0}", setting_result)
current_value = setting_result.get("result", None)
if current_value is not None:
current_value = current_value.get("value", -1)
@@ -73,7 +208,7 @@ def playFile(play_info):
if return_value:
params = {"setting": "myvideos.selectaction", "value": 2}
json_rpc_result = json_rpc('Settings.setSettingValue').execute(params)
- log.debug("Save Setting (myvideos.selectaction): %s" % json_rpc_result)
+ log.debug("Save Setting (myvideos.selectaction): {0}", json_rpc_result)
if resume_result == 1:
seekTime = 0
@@ -81,20 +216,21 @@ def playFile(play_info):
return
listitem_props = []
+ playback_type = "0"
playurl = None
play_session_id = id_generator()
- log.debug("play_session_id: %s" % play_session_id)
+ log.debug("play_session_id: {0}", play_session_id)
# check if strm file, path will contain contain strm contents
- if result.get('MediaSources'):
- source = result['MediaSources'][0]
- if source.get('Container') == 'strm':
- playurl, listitem_props = PlayUtils().getStrmDetails(result)
+ if selected_media_source.get('Container') == 'strm':
+ playurl, listitem_props = PlayUtils().getStrmDetails(selected_media_source)
+ if playurl is None:
+ return
if not playurl:
- playurl, playback_type = PlayUtils().getPlayUrl(id, result, force_transcode, play_session_id)
+ playurl, playback_type = PlayUtils().getPlayUrl(id, selected_media_source, force_transcode, play_session_id)
- log.debug("Play URL: " + playurl + " ListItem Properties: " + str(listitem_props))
+ log.debug("Play URL: {0} ListItem Properties: {1}", playurl, listitem_props)
playback_type_string = "DirectPlay"
if playback_type == "2":
@@ -102,37 +238,31 @@ def playFile(play_info):
elif playback_type == "1":
playback_type_string = "DirectStream"
- home_window = HomeWindow()
- home_window.setProperty("PlaybackType_" + id, playback_type_string)
- home_window.setProperty("PlaySessionId_" + id, play_session_id)
-
# add the playback type into the overview
if result.get("Overview", None) is not None:
result["Overview"] = playback_type_string + "\n" + result.get("Overview")
else:
result["Overview"] = playback_type_string
+ # add title decoration is needed
item_title = result.get("Name", i18n('missing_title'))
- add_episode_number = settings.getSetting('addEpisodeNumber') == 'true'
- if result.get("Type") == "Episode" and add_episode_number:
- episode_num = result.get("IndexNumber")
- if episode_num is not None:
- if episode_num < 10:
- episode_num = "0" + str(episode_num)
- else:
- episode_num = str(episode_num)
- else:
- episode_num = ""
- item_title = episode_num + " - " + item_title
-
list_item = xbmcgui.ListItem(label=item_title)
- # if transcoding then prompt for audio and subtitle
- if playback_type == "2":
- playurl = audioSubsPref(playurl, list_item, result)
- log.debug("New playurl for transcoding : " + playurl)
- elif playback_type == "1":
- externalSubs(result, list_item)
+ if playback_type == "2": # if transcoding then prompt for audio and subtitle
+ playurl = audioSubsPref(playurl, list_item, selected_media_source, id, use_default)
+ log.debug("New playurl for transcoding: {0}", playurl)
+
+ elif playback_type == "1": # for direct stream add any streamable subtitles
+ externalSubs(selected_media_source, list_item, id)
+
+ # add playurl and data to the monitor
+ data = {}
+ data["item_id"] = id
+ data["playback_type"] = playback_type_string
+ data["play_session_id"] = play_session_id
+ data["play_action_type"] = "play"
+ monitor.played_information[playurl] = data
+ log.debug("Add to played_information: {0}", monitor.played_information)
list_item.setPath(playurl)
list_item = setListItemProps(id, list_item, result, server, listitem_props, item_title)
@@ -142,6 +272,8 @@ def playFile(play_info):
playlist.add(playurl, list_item)
xbmc.Player().play(playlist)
+ send_next_episode_details(result)
+
if seekTime == 0:
return
@@ -156,18 +288,74 @@ def playFile(play_info):
seekTime = seekTime - jump_back_amount
- while xbmc.Player().getTime() < (seekTime - 5):
+ target_seek = (seekTime - 5)
+ current_position = 0
+ while current_position < target_seek:
# xbmc.Player().pause()
xbmc.sleep(100)
xbmc.Player().seekTime(seekTime)
xbmc.sleep(100)
# xbmc.Player().play()
+ current_position = xbmc.Player().getTime()
+ log.debug("Playback_Start_Seek target:{0} current:{1}", target_seek, current_position)
+
+
+def send_next_episode_details(item):
+
+ next_episode = get_next_episode(item)
+
+ if next_episode is None:
+ log.debug("No next episode")
+ return
+
+ gui_options = {}
+ gui_options["server"] = download_utils.getServer()
+
+ gui_options["name_format"] = None
+ gui_options["name_format_type"] = ""
+
+ item_details = extract_item_info(item, gui_options)
+ next_item_details = extract_item_info(next_episode, gui_options)
+
+ current_item = {}
+ current_item["id"] = item_details.id
+ current_item["title"] = item_details.name
+ current_item["image"] = item_details.art.get('tvshow.poster', '')
+ current_item["thumb"] = item_details.art.get('thumb', '')
+ current_item["fanartimage"] = item_details.art.get('tvshow.fanart', '')
+ current_item["overview"] = item_details.plot
+ current_item["tvshowtitle"] = item_details.series_name
+ current_item["playcount"] = item_details.play_count
+ current_item["season"] = item_details.season_number
+ current_item["episode"] = item_details.episode_number
+ current_item["rating"] = item_details.critic_rating
+ current_item["year"] = item_details.year
+
+ next_item = {}
+ next_item["id"] = next_item_details.id
+ next_item["title"] = next_item_details.name
+ next_item["image"] = next_item_details.art.get('tvshow.poster', '')
+ next_item["thumb"] = next_item_details.art.get('thumb', '')
+ next_item["fanartimage"] = next_item_details.art.get('tvshow.fanart', '')
+ next_item["overview"] = next_item_details.plot
+ next_item["tvshowtitle"] = next_item_details.series_name
+ next_item["playcount"] = next_item_details.play_count
+ next_item["season"] = next_item_details.season_number
+ next_item["episode"] = next_item_details.episode_number
+ next_item["rating"] = next_item_details.critic_rating
+ next_item["year"] = next_item_details.year
+
+ next_info = {
+ "current_item": current_item,
+ "next_item": next_item
+ }
+
+ log.debug("send_next_episode_details: {0}", next_info)
+ send_event_notification("embycon_next_episode", next_info)
+
def setListItemProps(id, listItem, result, server, extra_props, title):
# set up item and item info
- thumbID = id
- eppNum = -1
- seasonNum = -1
art = getArt(result, server=server)
listItem.setIconImage(art['thumb']) # back compat
@@ -175,34 +363,69 @@ def setListItemProps(id, listItem, result, server, extra_props, title):
listItem.setProperty('discart', art['discart']) # not avail to setArt
listItem.setArt(art)
- listItem.setProperty('IsPlayable', 'true')
+ listItem.setProperty('IsPlayable', 'false')
listItem.setProperty('IsFolder', 'false')
listItem.setProperty('id', result.get("Id"))
for prop in extra_props:
listItem.setProperty(prop[0], prop[1])
- # play info
- details = {
- 'title': title,
- 'plot': result.get("Overview")
- }
+ item_type = result.get("Type", "").lower()
+ mediatype = 'video'
- if (eppNum > -1):
- details["episode"] = str(eppNum)
+ if item_type == 'movie' or item_type == 'boxset':
+ mediatype = 'movie'
+ elif item_type == 'series':
+ mediatype = 'tvshow'
+ elif item_type == 'season':
+ mediatype = 'season'
+ elif item_type == 'episode':
+ mediatype = 'episode'
+ elif item_type == 'audio':
+ mediatype = 'song'
- if (seasonNum > -1):
- details["season"] = str(seasonNum)
+ if item_type == "audio":
- listItem.setInfo("Video", infoLabels=details)
+ details = {
+ 'title': title,
+ 'mediatype': mediatype
+ }
+ listItem.setInfo("Music", infoLabels=details)
+
+ else:
+
+ details = {
+ 'title': title,
+ 'plot': result.get("Overview"),
+ 'mediatype': mediatype
+ }
+
+ tv_show_name = result.get("SeriesName")
+ if tv_show_name is not None:
+ details['tvshowtitle'] = tv_show_name
+
+ if item_type == "episode":
+ episode_number = result.get("IndexNumber", -1)
+ details["episode"] = str(episode_number)
+ season_number = result.get("ParentIndexNumber", -1)
+ details["season"] = str(season_number)
+ elif item_type == "season":
+ season_number = result.get("IndexNumber", -1)
+ details["season"] = str(season_number)
+
+ details["plotoutline"] = "emby_id:" + id
+ #listItem.setUniqueIDs({'emby': id})
+
+ listItem.setInfo("Video", infoLabels=details)
return listItem
+
# For transcoding only
# Present the list of audio and subtitles to select from
# for external streamable subtitles add the URL to the Kodi item and let Kodi handle it
# else ask for the subtitles to be burnt in when transcoding
-def audioSubsPref(url, list_item, emby_item):
+def audioSubsPref(url, list_item, media_source, item_id, use_default):
dialog = xbmcgui.Dialog()
audioStreamsList = {}
@@ -214,14 +437,12 @@ def audioSubsPref(url, list_item, emby_item):
selectAudioIndex = ""
selectSubsIndex = ""
playurlprefs = "%s" % url
+ default_audio = media_source.get('DefaultAudioStreamIndex', 1)
+ default_sub = media_source.get('DefaultSubtitleStreamIndex', "")
- try:
- mediasources = emby_item['MediaSources'][0]
- mediastreams = mediasources['MediaStreams']
- except (TypeError, KeyError, IndexError):
- return
+ media_streams = media_source['MediaStreams']
- for stream in mediastreams:
+ for stream in media_streams:
# Since Emby returns all possible tracks together, have to sort them.
index = stream['Index']
@@ -258,7 +479,10 @@ def audioSubsPref(url, list_item, emby_item):
subtitleStreamsList[track] = index
subtitleStreams.append(track)
- if len(audioStreams) > 1:
+ if use_default:
+ playurlprefs += "&AudioStreamIndex=%s" % default_audio
+
+ elif len(audioStreams) > 1:
resp = dialog.select(i18n('select_audio_stream'), audioStreams)
if resp > -1:
# User selected audio
@@ -266,35 +490,38 @@ def audioSubsPref(url, list_item, emby_item):
selectAudioIndex = audioStreamsList[selected]
playurlprefs += "&AudioStreamIndex=%s" % selectAudioIndex
else: # User backed out of selection
- playurlprefs += "&AudioStreamIndex=%s" % mediasources['DefaultAudioStreamIndex']
- else: # There's only one audiotrack.
+ playurlprefs += "&AudioStreamIndex=%s" % default_audio
+
+ elif len(audioStreams) == 1: # There's only one audiotrack.
selectAudioIndex = audioStreamsList[audioStreams[0]]
playurlprefs += "&AudioStreamIndex=%s" % selectAudioIndex
if len(subtitleStreams) > 1:
- resp = dialog.select(i18n('select_subtitle'), subtitleStreams)
- if resp == 0:
- # User selected no subtitles
- pass
- elif resp > -1:
- # User selected subtitles
- selected = subtitleStreams[resp]
- selectSubsIndex = subtitleStreamsList[selected]
-
- # Load subtitles in the listitem if downloadable
- if selectSubsIndex in downloadableStreams:
-
- itemid = emby_item['Id']
- url = [("%s/Videos/%s/%s/Subtitles/%s/Stream.srt"
- % (downloadUtils.getServer(), itemid, itemid, selectSubsIndex))]
- log.debug("Streaming subtitles url: %s %s" % (selectSubsIndex, url))
- list_item.setSubtitles(url)
- else:
- # Burn subtitles
- playurlprefs += "&SubtitleStreamIndex=%s" % selectSubsIndex
+ if use_default:
+ playurlprefs += "&SubtitleStreamIndex=%s" % default_sub
- else: # User backed out of selection
- playurlprefs += "&SubtitleStreamIndex=%s" % mediasources.get('DefaultSubtitleStreamIndex', "")
+ else:
+ resp = dialog.select(i18n('select_subtitle'), subtitleStreams)
+ if resp == 0:
+ # User selected no subtitles
+ pass
+ elif resp > -1:
+ # User selected subtitles
+ selected = subtitleStreams[resp]
+ selectSubsIndex = subtitleStreamsList[selected]
+
+ # Load subtitles in the listitem if downloadable
+ if selectSubsIndex in downloadableStreams:
+ url = [("%s/Videos/%s/%s/Subtitles/%s/Stream.srt"
+ % (download_utils.getServer(), item_id, item_id, selectSubsIndex))]
+ log.debug("Streaming subtitles url: {0} {1}", selectSubsIndex, url)
+ list_item.setSubtitles(url)
+ else:
+ # Burn subtitles
+ playurlprefs += "&SubtitleStreamIndex=%s" % selectSubsIndex
+
+ else: # User backed out of selection
+ playurlprefs += "&SubtitleStreamIndex=%s" % default_sub
# Get number of channels for selected audio track
audioChannels = audioStreamsChannelsList.get(selectAudioIndex, 0)
@@ -305,17 +532,14 @@ def audioSubsPref(url, list_item, emby_item):
return playurlprefs
+
# direct stream, set any available subtitle streams
-def externalSubs(emby_item, list_item):
+def externalSubs(media_source, list_item, item_id):
externalsubs = []
- itemid = emby_item['Id']
- try:
- mediastreams = emby_item['MediaSources'][0]['MediaStreams']
- except (TypeError, KeyError, IndexError):
- return
+ media_streams = media_source['MediaStreams']
- for stream in mediastreams:
+ for stream in media_streams:
if (stream['Type'] == "Subtitle"
and stream['IsExternal']
@@ -324,8 +548,273 @@ def externalSubs(emby_item, list_item):
index = stream['Index']
url = ("%s/Videos/%s/%s/Subtitles/%s/Stream.%s"
- % (downloadUtils.getServer(), itemid, itemid, index, stream['Codec']))
+ % (download_utils.getServer(), item_id, item_id, index, stream['Codec']))
externalsubs.append(url)
- list_item.setSubtitles(externalsubs) \ No newline at end of file
+ list_item.setSubtitles(externalsubs)
+
+
+def sendProgress(monitor):
+ playing_file = xbmc.Player().getPlayingFile()
+
+ '''
+ video_tag_info = xbmc.Player().getVideoInfoTag()
+ plotoutline = video_tag_info.getPlotOutline()
+ log.debug("Player().getVideoInfoTag().getPlotOutline(): {0}", plotoutline)
+ emby_id = None
+ if plotoutline is not None and plotoutline.startswith("emby_id:"):
+ emby_id = plotoutline[8:]
+ log.debug("EmbyId: {0}", emby_id)
+ '''
+
+ 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
+ play_data["currently_playing"] = True
+
+ 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: {0}", postdata)
+
+ url = "{server}/emby/Sessions/Playing/Progress"
+ download_utils.downloadUrl(url, postBody=postdata, method="POST")
+
+
+@catch_except()
+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")
+ result = json.loads(jsonData)
+
+ if result is None:
+ log.debug("promptForStopActions failed! no result from server.")
+ return
+
+ 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: {0}", 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: {0}", 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):
+
+ next_episode = get_next_episode(result)
+
+ if next_episode is not None:
+ resp = True
+ index = next_episode.get("IndexNumber", -1)
+ if play_prompt:
+ next_epp_name = "%02d - %s" % (index, next_episode.get("Name", "n/a"))
+ resp = xbmcgui.Dialog().yesno(i18n("play_next_title"), i18n("play_next_question"), next_epp_name, autoclose=10000)
+
+ if resp:
+ next_item_id = next_episode.get("Id")
+ log.debug("Playing Next Episode: {0}", next_item_id)
+
+ play_info = {}
+ play_info["item_id"] = next_item_id
+ play_info["auto_resume"] = "-1"
+ play_info["force_transcode"] = False
+ send_event_notification("embycon_play_action", play_info)
+
+
+@catch_except()
+def stopAll(played_information):
+ if len(played_information) == 0:
+ return
+
+ log.debug("played_information: {0}", played_information)
+
+ for item_url in played_information:
+ data = played_information.get(item_url)
+ if data.get("currently_playing", False) is True:
+ log.debug("item_url: {0}", item_url)
+ log.debug("item_data: {0}", data)
+
+ current_possition = data.get("currentPossition", 0)
+ emby_item_id = data.get("item_id")
+
+ if emby_item_id is not None and len(emby_item_id) != 0 and emby_item_id != "None":
+ log.debug("Playback Stopped at: {0}", current_possition)
+
+ 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")
+ data["currently_playing"] = False
+
+ if data.get("play_action_type", "") == "play":
+ promptForStopActions(emby_item_id, current_possition)
+
+
+class Service(xbmc.Player):
+
+ def __init__(self, *args):
+ log.debug("Starting monitor service: {0}", 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: {0}", current_playing_file)
+ log.debug("played_information: {0}", self.played_information)
+
+ if current_playing_file not in self.played_information:
+ log.debug("This file was not started by EmbyCon")
+ return
+
+ data = self.played_information[current_playing_file]
+ data["paused"] = False
+ data["currently_playing"] = True
+
+ emby_item_id = data["item_id"]
+ playback_type = data["playback_type"]
+ play_session_id = data["play_session_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: {0}", postdata)
+
+ url = "{server}/emby/Sessions/Playing"
+ download_utils.downloadUrl(url, postBody=postdata, method="POST")
+
+ def onPlayBackEnded(self):
+ # Will be called when kodi stops playing a file
+ log.debug("EmbyCon Service -> onPlayBackEnded")
+ stopAll(self.played_information)
+
+ def onPlayBackStopped(self):
+ # Will be called when user stops kodi playing a file
+ log.debug("onPlayBackStopped")
+ stopAll(self.played_information)
+
+ def onPlayBackPaused(self):
+ # Will be called when kodi pauses the video
+ log.debug("onPlayBackPaused")
+ current_file = xbmc.Player().getPlayingFile()
+ play_data = self.played_information.get(current_file)
+
+ if play_data is not None:
+ play_data['paused'] = True
+ sendProgress(self)
+
+ def onPlayBackResumed(self):
+ # Will be called when kodi resumes the video
+ log.debug("onPlayBackResumed")
+ current_file = xbmc.Player().getPlayingFile()
+ play_data = self.played_information.get(current_file)
+
+ if play_data is not None:
+ play_data['paused'] = False
+ sendProgress(self)
+
+ def onPlayBackSeek(self, time, seekOffset):
+ # Will be called when kodi seeks in video
+ log.debug("onPlayBackSeek")
+ sendProgress(self)
+
+
+class PlaybackService(xbmc.Monitor):
+
+ def __init__(self, monitor):
+ self.monitor = monitor
+
+ def onNotification(self, sender, method, data):
+ log.debug("PlaybackService:onNotification:{0}:{1}:{2}", sender, method, data)
+ if sender[-7:] != '.SIGNAL':
+ return
+
+ signal = method.split('.', 1)[-1]
+ if signal != "embycon_play_action":
+ return
+
+ data_json = json.loads(data)
+ hex_data = data_json[0]
+ log.debug("PlaybackService:onNotification:{0}", hex_data)
+ decoded_data = binascii.unhexlify(hex_data)
+ play_info = json.loads(decoded_data)
+ playFile(play_info, self.monitor)