Revamp playback start, part 5
This commit is contained in:
parent
2791da9f65
commit
287b888b6f
7 changed files with 109 additions and 9 deletions
|
@ -1505,6 +1505,16 @@ class API():
|
|||
"""
|
||||
return self.item.attrib.get('year', None)
|
||||
|
||||
def getResume(self):
|
||||
"""
|
||||
Returns the resume point of time in seconds as int. 0 if not found
|
||||
"""
|
||||
try:
|
||||
resume = float(self.item.attrib['viewOffset'])
|
||||
except (KeyError, ValueError):
|
||||
resume = 0.0
|
||||
return int(resume * v.PLEX_TO_KODI_TIMEFACTOR)
|
||||
|
||||
def getRuntime(self):
|
||||
"""
|
||||
Resume point of time and runtime/totaltime in rounded to seconds.
|
||||
|
@ -2521,7 +2531,9 @@ class API():
|
|||
'mpaa': self.getMpaa(),
|
||||
'aired': self.getPremiereDate()
|
||||
}
|
||||
listItem.setProperty('resumetime', str(userdata['Resume']))
|
||||
# Do NOT set resumetime - otherwise Kodi always resumes at that time
|
||||
# even if the user chose to start element from the beginning
|
||||
# listItem.setProperty('resumetime', str(userdata['Resume']))
|
||||
listItem.setProperty('totaltime', str(userdata['Runtime']))
|
||||
|
||||
if typus == v.PLEX_TYPE_EPISODE:
|
||||
|
|
|
@ -3,11 +3,15 @@ PKC Kodi Monitoring implementation
|
|||
"""
|
||||
from logging import getLogger
|
||||
from json import loads
|
||||
from threading import Thread
|
||||
|
||||
from xbmc import Monitor, Player, sleep
|
||||
from xbmc import Monitor, Player, sleep, getCondVisibility, getInfoLabel, \
|
||||
getLocalizedString
|
||||
from xbmcgui import Window
|
||||
|
||||
import plexdb_functions as plexdb
|
||||
from utils import window, settings, CatchExceptions, plex_command
|
||||
from utils import window, settings, CatchExceptions, plex_command, \
|
||||
thread_methods
|
||||
from PlexFunctions import scrobble
|
||||
from kodidb_functions import kodiid_from_filename
|
||||
from plexbmchelper.subscribers import LOCKER
|
||||
|
@ -391,3 +395,31 @@ class KodiMonitor(Monitor):
|
|||
else:
|
||||
window('plex_%s.playmethod' % currentFile, value="DirectPlay")
|
||||
LOG.debug('Window properties set for direct paths!')
|
||||
|
||||
|
||||
@thread_methods
|
||||
class SpecialMonitor(Thread):
|
||||
"""
|
||||
Detect the resume dialog for widgets.
|
||||
Could also be used to detect external players (see Emby implementation)
|
||||
"""
|
||||
def run(self):
|
||||
LOG.info("----====# Starting Special Monitor #====----")
|
||||
player = Player()
|
||||
while not self.thread_stopped():
|
||||
is_playing = player.isPlaying()
|
||||
|
||||
if (not is_playing and
|
||||
getCondVisibility('Window.IsVisible(DialogContextMenu.xml)') and
|
||||
not getCondVisibility('Window.IsVisible(MyVideoNav.xml)') and
|
||||
getInfoLabel('Control.GetLabel(1002)') == getLocalizedString(12021)):
|
||||
control = int(Window(10106).getFocusId())
|
||||
if control == 1002:
|
||||
# Start from beginning
|
||||
LOG.info("Resume dialog: Start from beginning selected")
|
||||
state.RESUME_PLAYBACK = False
|
||||
else:
|
||||
LOG.info("Resume dialog: resume selected")
|
||||
state.RESUME_PLAYBACK = True
|
||||
sleep(200)
|
||||
LOG.info("#====---- Special Monitor Stopped ----====#")
|
||||
|
|
|
@ -32,7 +32,7 @@ def pickle_me(obj, window_var='plex_result'):
|
|||
obj can be pretty much any Python object. However, classes and
|
||||
functions won't work. See the Pickle documentation
|
||||
"""
|
||||
log('%sStart pickling: %s' % (PREFIX, obj), level=LOGDEBUG)
|
||||
log('%sStart pickling' % PREFIX, level=LOGDEBUG)
|
||||
pickl_window(window_var, value=dumps(obj))
|
||||
log('%sSuccessfully pickled' % PREFIX, level=LOGDEBUG)
|
||||
|
||||
|
|
|
@ -66,6 +66,44 @@ def playback_triage(plex_id=None, plex_type=None, path=None):
|
|||
conclude_playback(playqueue, pos)
|
||||
|
||||
|
||||
def play_resume(playqueue, xml, stack):
|
||||
"""
|
||||
If there exists a resume point, Kodi will ask the user whether to continue
|
||||
playback. We thus need to use setResolvedUrl "correctly". Mind that there
|
||||
might be several parts!
|
||||
"""
|
||||
result = Playback_Successful()
|
||||
listitem = PKC_ListItem()
|
||||
# Only get the very first item of our playqueue (i.e. the very first part)
|
||||
stack_item = stack.pop(0)
|
||||
api = API(xml[0])
|
||||
item = PL.playlist_item_from_xml(playqueue,
|
||||
xml[0],
|
||||
kodi_id=stack_item['kodi_id'],
|
||||
kodi_type=stack_item['kodi_type'])
|
||||
api.setPartNumber(item.part)
|
||||
item.playcount = stack_item['playcount']
|
||||
item.offset = stack_item['offset']
|
||||
item.part = stack_item['part']
|
||||
item.init_done = True
|
||||
api.CreateListItemFromPlexItem(listitem)
|
||||
playutils = PlayUtils(api, item)
|
||||
playurl = playutils.getPlayUrl()
|
||||
listitem.setPath(playurl)
|
||||
if item.playmethod in ('DirectStream', 'DirectPlay'):
|
||||
listitem.setSubtitles(api.externalSubs())
|
||||
else:
|
||||
playutils.audio_subtitle_prefs(listitem)
|
||||
result.listitem = listitem
|
||||
# Add to our playlist
|
||||
playqueue.items.append(item)
|
||||
# This will release default.py with setResolvedUrl
|
||||
pickle_me(result)
|
||||
# Add remaining parts to the playlist, if any
|
||||
if stack:
|
||||
_process_stack(playqueue, stack)
|
||||
|
||||
|
||||
def playback_init(plex_id, plex_type, playqueue):
|
||||
"""
|
||||
Playback setup if Kodi starts playing an item for the first time.
|
||||
|
@ -112,10 +150,16 @@ def playback_init(plex_id, plex_type, playqueue):
|
|||
playqueue.clear()
|
||||
PL.get_playlist_details_from_xml(playqueue, xml)
|
||||
stack = _prep_playlist_stack(xml)
|
||||
# if resume:
|
||||
# # Need to handle this differently so only 1 dialog is displayed whether
|
||||
# # user wants to resume to start at the beginning
|
||||
# LOG.info('Resume detected')
|
||||
# play_resume(playqueue, xml, stack)
|
||||
# return
|
||||
# Release our default.py before starting our own Kodi player instance
|
||||
pickle_me(Playback_Successful())
|
||||
# Sleep a bit to let setResolvedUrl do its thing - bit ugly
|
||||
sleep(200)
|
||||
sleep(100)
|
||||
_process_stack(playqueue, stack)
|
||||
# New thread to release this one sooner (e.g. harddisk spinning up)
|
||||
thread = Thread(target=Player().play,
|
||||
|
@ -138,7 +182,6 @@ def _prep_playlist_stack(xml):
|
|||
# We will never store clips (trailers) in the Kodi DB
|
||||
kodi_id = None
|
||||
kodi_type = None
|
||||
resume, _ = api.getRuntime()
|
||||
for part, _ in enumerate(item[0]):
|
||||
api.setPartNumber(part)
|
||||
if kodi_id is None:
|
||||
|
@ -164,7 +207,7 @@ def _prep_playlist_stack(xml):
|
|||
'listitem': listitem,
|
||||
'part': part,
|
||||
'playcount': api.getViewCount(),
|
||||
'offset': resume
|
||||
'offset': api.getResume()
|
||||
})
|
||||
return stack
|
||||
|
||||
|
@ -213,6 +256,7 @@ def conclude_playback(playqueue, pos):
|
|||
start playback
|
||||
return PKC listitem attached to result
|
||||
"""
|
||||
LOG.info('Concluding playback for playqueue position %s', pos)
|
||||
result = Playback_Successful()
|
||||
listitem = PKC_ListItem()
|
||||
item = playqueue.items[pos]
|
||||
|
@ -226,10 +270,16 @@ def conclude_playback(playqueue, pos):
|
|||
else:
|
||||
playurl = item.file
|
||||
listitem.setPath(playurl)
|
||||
if item.playmethod in ("DirectStream", "DirectPlay"):
|
||||
if item.playmethod in ('DirectStream', 'DirectPlay'):
|
||||
listitem.setSubtitles(api.externalSubs())
|
||||
else:
|
||||
playutils.audio_subtitle_prefs(listitem)
|
||||
listitem.setPath(playurl)
|
||||
if state.RESUME_PLAYBACK is True:
|
||||
state.RESUME_PLAYBACK = False
|
||||
LOG.info('Resuming playback at %s', item.offset)
|
||||
listitem.setProperty('StartOffset', str(item.offset))
|
||||
listitem.setProperty('resumetime', str(item.offset))
|
||||
result.listitem = listitem
|
||||
pickle_me(result)
|
||||
LOG.info('Done concluding playback')
|
||||
|
|
|
@ -47,6 +47,7 @@ class PlayUtils():
|
|||
})
|
||||
self.item.playmethod = 'Transcode'
|
||||
LOG.info("The playurl is: %s", playurl)
|
||||
self.item.file = playurl
|
||||
return playurl
|
||||
|
||||
def isDirectPlay(self):
|
||||
|
|
|
@ -128,6 +128,9 @@ PLAYSTATE = {
|
|||
# paths for playback (since we're not receiving a Kodi id)
|
||||
PLEX_IDS = {}
|
||||
PLAYED_INFO = {}
|
||||
# Set by SpecialMonitor - did user choose to resume playback or start from the
|
||||
# beginning?
|
||||
RESUME_PLAYBACK = False
|
||||
|
||||
# Kodi webserver details
|
||||
WEBSERVER_PORT = 8080
|
||||
|
|
|
@ -31,7 +31,7 @@ sys_path.append(_base_resource)
|
|||
from utils import settings, window, language as lang, dialog, tryDecode
|
||||
from userclient import UserClient
|
||||
import initialsetup
|
||||
from kodimonitor import KodiMonitor
|
||||
from kodimonitor import KodiMonitor, SpecialMonitor
|
||||
from librarysync import LibrarySync
|
||||
import videonodes
|
||||
from websocket_client import PMS_Websocket, Alexa_Websocket
|
||||
|
@ -155,6 +155,7 @@ class Service():
|
|||
self.alexa = Alexa_Websocket()
|
||||
self.library = LibrarySync()
|
||||
self.plexCompanion = PlexCompanion()
|
||||
self.specialMonitor = SpecialMonitor()
|
||||
self.playback_starter = Playback_Starter()
|
||||
if settings('enableTextureCache') == "true":
|
||||
self.image_cache_thread = Image_Cache_Thread()
|
||||
|
@ -197,6 +198,7 @@ class Service():
|
|||
sound=False)
|
||||
# Start monitoring kodi events
|
||||
self.kodimonitor_running = KodiMonitor()
|
||||
self.specialMonitor.start()
|
||||
# Start the Websocket Client
|
||||
if not self.ws_running:
|
||||
self.ws_running = True
|
||||
|
|
Loading…
Reference in a new issue