Revamp playback start, part 6

This commit is contained in:
croneter 2018-01-25 17:15:38 +01:00
parent 510952f9de
commit cfff75926a
5 changed files with 93 additions and 93 deletions

View file

@ -415,6 +415,10 @@ class InitialSetup():
# Disable cleaning of library - not compatible with PKC
xml.set_setting(['videolibrary', 'cleanonupdate'],
value='false')
# Set completely watched point same as plex (and not 92%)
xml.set_setting(['video', 'ignorepercentatend'], value='10')
xml.set_setting(['video', 'playcountminimumpercent'],
value='90')
reboot = xml.write_xml
except etree.ParseError:
cache = None

View file

@ -14,6 +14,7 @@ from utils import window, settings, plex_command, thread_methods
from PlexFunctions import scrobble
from kodidb_functions import kodiid_from_filename
from plexbmchelper.subscribers import LOCKER
from playback import playback_triage
import playqueue as PQ
import json_rpc as js
import playlist_func as PL
@ -60,6 +61,7 @@ class KodiMonitor(Monitor):
Monitor.__init__(self)
for playerid in state.PLAYER_STATES:
state.PLAYER_STATES[playerid] = dict(state.PLAYSTATE)
state.OLD_PLAYER_STATES[playerid] = dict(state.PLAYSTATE)
LOG.info("Kodi monitor started.")
def onScanStarted(self, library):
@ -143,32 +145,34 @@ class KodiMonitor(Monitor):
# Manually marking as watched/unwatched
playcount = data.get('playcount')
item = data.get('item')
if playcount is None or item is None:
return
try:
kodiid = item['id']
item_type = item['type']
except (KeyError, TypeError):
LOG.info("Item is invalid for playstate update.")
return
# Send notification to the server.
with plexdb.Get_Plex_DB() as plexcur:
plex_dbitem = plexcur.getItem_byKodiId(kodiid, item_type)
try:
itemid = plex_dbitem[0]
except TypeError:
LOG.error("Could not find itemid in plex database for a "
"video library update")
else:
# Send notification to the server.
with plexdb.Get_Plex_DB() as plexcur:
plex_dbitem = plexcur.getItem_byKodiId(kodiid, item_type)
try:
itemid = plex_dbitem[0]
except TypeError:
LOG.error("Could not find itemid in plex database for a "
"video library update")
# Stop from manually marking as watched unwatched, with
# actual playback.
if window('plex_skipWatched%s' % itemid) == "true":
# property is set in player.py
window('plex_skipWatched%s' % itemid, clear=True)
else:
# Stop from manually marking as watched unwatched, with
# actual playback.
if window('plex_skipWatched%s' % itemid) == "true":
# property is set in player.py
window('plex_skipWatched%s' % itemid, clear=True)
# notify the server
if playcount > 0:
scrobble(itemid, 'watched')
else:
# notify the server
if playcount > 0:
scrobble(itemid, 'watched')
else:
scrobble(itemid, 'unwatched')
scrobble(itemid, 'unwatched')
elif method == "VideoLibrary.OnRemove":
pass
elif method == "System.OnSleep":
@ -202,6 +206,21 @@ class KodiMonitor(Monitor):
Will NOT be called if playback initiated by Kodi widgets
"""
playqueue = PQ.PLAYQUEUES[data['playlistid']]
# Kodi remembers the last setResolvedUrl - which is empty in our case
kodi_item = js.get_item(data['playlistid'])
LOG.debug('kodi_item: %s', kodi_item)
# if kodi_item.get('file') == '':
# LOG.info('Detected re-start of playback of last item')
# old = state.OLD_PLAYER_STATES[data['playlistid']]
# kwargs = {
# 'plex_id': old['plex_id'],
# 'plex_type': old['plex_type'],
# 'path': old['file'],
# 'resolve': False
# }
# thread = Thread(target=playback_triage, kwargs=kwargs)
# thread.start()
# return
# Have we initiated the playqueue already? If not, ignore this
if not playqueue.items:
LOG.debug('Playqueue not initiated - ignoring')
@ -211,11 +230,10 @@ class KodiMonitor(Monitor):
LOG.debug('PKC added this item to the playqueue - ignoring')
return
# Check whether we even need to update our known playqueue
kodi_playqueue = js.playlist_get_items(data['playlistid'])
if playqueue.old_kodi_pl == kodi_playqueue:
# We already know the latest playqueue (e.g. because Plex
# initiated playback)
return
# if playqueue.old_kodi_pl == kodi_playqueue:
# # We already know the latest playqueue (e.g. because Plex
# # initiated playback)
# return
# Playlist has been updated; need to tell Plex about it
if playqueue.id is None:
PL.init_Plex_playlist(playqueue, kodi_item=data['item'])
@ -224,7 +242,7 @@ class KodiMonitor(Monitor):
data['position'],
kodi_item=data['item'])
# Make sure that we won't re-add this item
playqueue.old_kodi_pl = kodi_playqueue
# playqueue.old_kodi_pl = kodi_playqueue
@LOCKER.lockthis
def _playlist_onremove(self, data):

View file

@ -29,7 +29,7 @@ LOG = getLogger("PLEX." + __name__)
@LOCKER.lockthis
def playback_triage(plex_id=None, plex_type=None, path=None):
def playback_triage(plex_id=None, plex_type=None, path=None, resolve=True):
"""
Hit this function for addon path playback, Plex trailers, etc.
Will setup playback first, then on second call complete playback.
@ -40,6 +40,10 @@ def playback_triage(plex_id=None, plex_type=None, path=None):
If trailers or additional (movie-)parts are added, default.py is released
and a completely new player instance is called with a new playlist. This
circumvents most issues with Kodi & playqueues
Set resolve to False if you do not want setResolvedUrl to be called on
the first pass - e.g. if you're calling this function from the original
service.py Python instance
"""
LOG.info('playback_triage called with plex_id %s, plex_type %s, path %s',
plex_id, plex_type, path)
@ -61,9 +65,10 @@ def playback_triage(plex_id=None, plex_type=None, path=None):
playqueue.items[pos]
except IndexError:
# Release our default.py before starting our own Kodi player instance
result = Playback_Successful()
result.listitem = PKC_ListItem()
pickle_me(result)
if resolve is True:
result = Playback_Successful()
result.listitem = PKC_ListItem(path='PKC_Dummy_Path')
pickle_me(result)
playback_init(plex_id, plex_type, playqueue)
else:
# kick off playback on second pass

View file

@ -5,10 +5,8 @@ from logging import getLogger
from xbmc import Player
from utils import window, DateToKodi, getUnixTimestamp, kodi_time_to_millis
from utils import window
from downloadutils import DownloadUtils as DU
import plexdb_functions as plexdb
import kodidb_functions as kodidb
from plexbmchelper.subscribers import LOCKER
import variables as v
import state
@ -20,6 +18,35 @@ LOG = getLogger("PLEX." + __name__)
###############################################################################
@LOCKER.lockthis
def playback_cleanup():
"""
PKC cleanup after playback ends/is stopped
"""
# We might have saved a transient token from a user flinging media via
# Companion (if we could not use the playqueue to store the token)
state.PLEX_TRANSIENT_TOKEN = None
for item in ('plex_customplaylist',
'plex_customplaylist.seektime',
'plex_forcetranscode'):
window(item, clear=True)
for playerid in state.ACTIVE_PLAYERS:
status = state.PLAYER_STATES[playerid]
# Remember the last played item later
state.OLD_PLAYER_STATES[playerid] = dict(status)
# Stop transcoding
if status['playmethod'] == 'Transcode':
LOG.info('Tell the PMS to stop transcoding')
DU().downloadUrl(
'{server}/video/:/transcode/universal/stop',
parameters={'session': v.PKC_MACHINE_IDENTIFIER})
# Reset the player's status
status = dict(state.PLAYSTATE)
# As all playback has halted, reset the players that have been active
state.ACTIVE_PLAYERS = []
LOG.info('Finished PKC playback cleanup')
class PKC_Player(Player):
def __init__(self):
Player.__init__(self)
@ -54,71 +81,11 @@ class PKC_Player(Player):
Will be called when playback is stopped by the user
"""
LOG.info("ONPLAYBACK_STOPPED")
self.cleanup_playback()
playback_cleanup()
def onPlayBackEnded(self):
"""
Will be called when playback ends due to the media file being finished
"""
LOG.info("ONPLAYBACK_ENDED")
self.cleanup_playback()
@LOCKER.lockthis
def cleanup_playback(self):
"""
PKC cleanup after playback ends/is stopped
"""
# We might have saved a transient token from a user flinging media via
# Companion (if we could not use the playqueue to store the token)
state.PLEX_TRANSIENT_TOKEN = None
for item in ('plex_currently_playing_itemid',
'plex_customplaylist',
'plex_customplaylist.seektime',
'plex_forcetranscode'):
window(item, clear=True)
for playerid in state.ACTIVE_PLAYERS:
status = state.PLAYER_STATES[playerid]
# Check whether we need to mark an item as completely watched
if not status['kodi_id'] or not status['plex_id']:
LOG.info('No PKC info safed for the element just played by Kodi'
' player %s', playerid)
continue
# Stop transcoding
if status['playmethod'] == 'Transcode':
LOG.info('Tell the PMS to stop transcoding')
DU().downloadUrl(
'{server}/video/:/transcode/universal/stop',
parameters={'session': v.PKC_MACHINE_IDENTIFIER})
if status['plex_type'] == v.PLEX_TYPE_SONG:
LOG.debug('Song has been played, not cleaning up playstate')
continue
resume = kodi_time_to_millis(status['time'])
runtime = kodi_time_to_millis(status['totaltime'])
LOG.info('Item playback progress %s out of %s', resume, runtime)
if not resume or not runtime:
continue
complete = float(resume) / float(runtime)
LOG.info("Percent complete: %s. Mark played at: %s",
complete, v.MARK_PLAYED_AT)
if complete >= v.MARK_PLAYED_AT:
# Tell Kodi that we've finished watching (Plex knows)
with plexdb.Get_Plex_DB() as plex_db:
plex_dbitem = plex_db.getItem_byId(status['plex_id'])
file_id = plex_dbitem[1] if plex_dbitem else None
if file_id is None:
LOG.error('No file_id found for %s', status)
continue
with kodidb.GetKodiDB('video') as kodi_db:
kodi_db.addPlaystate(
file_id,
None,
None,
status['playcount'] + 1,
DateToKodi(getUnixTimestamp()))
LOG.info('Marked plex element %s as completely watched',
status['plex_id'])
# As all playback has halted, reset the players that have been active
state.ACTIVE_PLAYERS = []
for playerid in state.PLAYER_STATES:
state.PLAYER_STATES[playerid] = dict(state.PLAYSTATE)
LOG.info('Finished PKC playback cleanup')
playback_cleanup()

View file

@ -91,6 +91,12 @@ PLAYER_STATES = {
2: {},
3: {}
}
# The LAST playstate once playback is finished
OLD_PLAYER_STATES = {
1: {},
2: {},
3: {}
}
# "empty" dict for the PLAYER_STATES above
PLAYSTATE = {
'type': None,