2015-12-25 07:07:00 +11:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
2016-03-17 03:02:22 +11:00
|
|
|
###############################################################################
|
2017-12-10 00:35:08 +11:00
|
|
|
from logging import getLogger
|
2018-03-12 04:54:05 +11:00
|
|
|
import copy
|
2015-12-25 07:07:00 +11:00
|
|
|
|
2018-03-23 03:26:11 +11:00
|
|
|
import xbmc
|
2015-12-25 07:07:00 +11:00
|
|
|
|
2018-03-12 06:10:02 +11:00
|
|
|
import kodidb_functions as kodidb
|
|
|
|
import plexdb_functions as plexdb
|
2018-01-22 04:31:49 +11:00
|
|
|
from downloadutils import DownloadUtils as DU
|
|
|
|
from plexbmchelper.subscribers import LOCKER
|
2018-03-12 06:10:02 +11:00
|
|
|
from utils import kodi_time_to_millis, unix_date_to_kodi, unix_timestamp
|
2017-01-25 02:04:42 +11:00
|
|
|
import variables as v
|
2017-05-18 04:22:16 +10:00
|
|
|
import state
|
2015-12-25 07:07:00 +11:00
|
|
|
|
2016-03-17 03:02:22 +11:00
|
|
|
###############################################################################
|
2015-12-25 07:07:00 +11:00
|
|
|
|
2017-12-10 00:35:08 +11:00
|
|
|
LOG = getLogger("PLEX." + __name__)
|
2016-09-02 03:41:55 +10:00
|
|
|
|
|
|
|
###############################################################################
|
|
|
|
|
2015-12-25 07:07:00 +11:00
|
|
|
|
2018-01-26 03:15:38 +11:00
|
|
|
@LOCKER.lockthis
|
2018-03-15 20:40:15 +11:00
|
|
|
def playback_cleanup(ended=False):
|
2018-01-26 03:15:38 +11:00
|
|
|
"""
|
2018-03-15 20:40:15 +11:00
|
|
|
PKC cleanup after playback ends/is stopped. Pass ended=True if Kodi
|
|
|
|
completely finished playing an item (because we will get and use wrong
|
|
|
|
timing data otherwise)
|
2018-01-26 03:15:38 +11:00
|
|
|
"""
|
2018-03-12 04:54:05 +11:00
|
|
|
LOG.debug('playback_cleanup called')
|
2018-01-26 03:15:38 +11:00
|
|
|
# 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 playerid in state.ACTIVE_PLAYERS:
|
|
|
|
status = state.PLAYER_STATES[playerid]
|
|
|
|
# Remember the last played item later
|
2018-03-12 04:57:00 +11:00
|
|
|
state.OLD_PLAYER_STATES[playerid] = copy.deepcopy(status)
|
2018-01-26 03:15:38 +11:00
|
|
|
# Stop transcoding
|
|
|
|
if status['playmethod'] == 'Transcode':
|
2018-02-04 00:05:18 +11:00
|
|
|
LOG.debug('Tell the PMS to stop transcoding')
|
2018-01-26 03:15:38 +11:00
|
|
|
DU().downloadUrl(
|
|
|
|
'{server}/video/:/transcode/universal/stop',
|
|
|
|
parameters={'session': v.PKC_MACHINE_IDENTIFIER})
|
2018-03-12 06:10:02 +11:00
|
|
|
if playerid == 1:
|
|
|
|
# Bookmarks might not be pickup up correctly, so let's do them
|
|
|
|
# manually. Applies to addon paths, but direct paths might have
|
|
|
|
# started playback via PMS
|
2018-03-15 20:40:15 +11:00
|
|
|
_record_playstate(status, ended)
|
2018-01-26 03:15:38 +11:00
|
|
|
# Reset the player's status
|
2018-03-12 04:54:05 +11:00
|
|
|
status = copy.deepcopy(state.PLAYSTATE)
|
2018-01-26 03:15:38 +11:00
|
|
|
# As all playback has halted, reset the players that have been active
|
|
|
|
state.ACTIVE_PLAYERS = []
|
2018-02-04 00:05:18 +11:00
|
|
|
LOG.debug('Finished PKC playback cleanup')
|
2018-01-26 03:15:38 +11:00
|
|
|
|
|
|
|
|
2018-03-15 20:40:15 +11:00
|
|
|
def _record_playstate(status, ended):
|
2018-03-15 20:25:51 +11:00
|
|
|
with kodidb.GetKodiDB('video') as kodi_db:
|
|
|
|
# Hack - remove any obsolete file entries Kodi made
|
|
|
|
kodi_db.clean_file_table()
|
2018-03-12 06:10:02 +11:00
|
|
|
if not status['plex_id']:
|
|
|
|
LOG.debug('No Plex id found to record playstate for status %s', status)
|
|
|
|
return
|
|
|
|
with plexdb.Get_Plex_DB() as plex_db:
|
|
|
|
kodi_db_item = plex_db.getItem_byId(status['plex_id'])
|
|
|
|
if kodi_db_item is None:
|
|
|
|
# Item not (yet) in Kodi library
|
|
|
|
LOG.debug('No playstate update due to Plex id not found: %s', status)
|
|
|
|
return
|
|
|
|
totaltime = float(kodi_time_to_millis(status['totaltime'])) / 1000
|
2018-03-15 20:40:15 +11:00
|
|
|
if ended:
|
|
|
|
progress = 0.99
|
|
|
|
time = v.IGNORE_SECONDS_AT_START + 1
|
|
|
|
else:
|
|
|
|
time = float(kodi_time_to_millis(status['time'])) / 1000
|
|
|
|
try:
|
|
|
|
progress = time / totaltime
|
|
|
|
except ZeroDivisionError:
|
|
|
|
progress = 0.0
|
|
|
|
LOG.debug('Playback progress %s (%s of %s seconds)',
|
|
|
|
progress, time, totaltime)
|
2018-03-12 06:10:02 +11:00
|
|
|
playcount = status['playcount']
|
2018-03-15 23:12:33 +11:00
|
|
|
last_played = unix_date_to_kodi(unix_timestamp())
|
2018-03-12 06:10:02 +11:00
|
|
|
if playcount is None:
|
|
|
|
LOG.info('playcount not found, looking it up in the Kodi DB')
|
|
|
|
with kodidb.GetKodiDB('video') as kodi_db:
|
|
|
|
playcount = kodi_db.get_playcount(kodi_db_item[1])
|
|
|
|
playcount = 0 if playcount is None else playcount
|
|
|
|
if time < v.IGNORE_SECONDS_AT_START:
|
|
|
|
LOG.debug('Ignoring playback less than %s seconds',
|
|
|
|
v.IGNORE_SECONDS_AT_START)
|
|
|
|
# Annoying Plex bug - it'll reset an already watched video to unwatched
|
2018-03-19 01:08:55 +11:00
|
|
|
playcount = None
|
2018-03-15 23:12:33 +11:00
|
|
|
last_played = None
|
2018-03-12 06:10:02 +11:00
|
|
|
time = 0
|
|
|
|
elif progress >= v.MARK_PLAYED_AT:
|
|
|
|
LOG.debug('Recording entirely played video since progress > %s',
|
|
|
|
v.MARK_PLAYED_AT)
|
|
|
|
playcount += 1
|
|
|
|
time = 0
|
|
|
|
with kodidb.GetKodiDB('video') as kodi_db:
|
|
|
|
kodi_db.addPlaystate(kodi_db_item[1],
|
|
|
|
time,
|
|
|
|
totaltime,
|
|
|
|
playcount,
|
2018-03-15 23:12:33 +11:00
|
|
|
last_played)
|
2018-03-23 03:26:11 +11:00
|
|
|
# Hack to force "in progress" widget to appear if it wasn't visible before
|
|
|
|
if (state.FORCE_RELOAD_SKIN and
|
|
|
|
xbmc.getCondVisibility('Window.IsVisible(Home.xml)')):
|
|
|
|
LOG.debug('Refreshing skin to update widgets')
|
|
|
|
xbmc.executebuiltin('ReloadSkin()')
|
2018-03-12 06:10:02 +11:00
|
|
|
|
|
|
|
|
2018-03-23 03:26:11 +11:00
|
|
|
class PKC_Player(xbmc.Player):
|
2015-12-25 07:07:00 +11:00
|
|
|
def __init__(self):
|
2018-03-23 03:26:11 +11:00
|
|
|
xbmc.Player.__init__(self)
|
2017-12-09 05:43:06 +11:00
|
|
|
LOG.info("Started playback monitor.")
|
2015-12-25 07:07:00 +11:00
|
|
|
|
2016-02-17 19:13:37 +11:00
|
|
|
def onPlayBackStarted(self):
|
2016-03-17 03:02:22 +11:00
|
|
|
"""
|
2016-09-02 03:41:55 +10:00
|
|
|
Will be called when xbmc starts playing a file.
|
2016-03-17 03:02:22 +11:00
|
|
|
"""
|
2018-01-22 04:31:49 +11:00
|
|
|
pass
|
2015-12-25 07:07:00 +11:00
|
|
|
|
2016-02-21 10:21:39 +11:00
|
|
|
def onPlayBackPaused(self):
|
2018-01-22 04:31:49 +11:00
|
|
|
"""
|
|
|
|
Will be called when playback is paused
|
|
|
|
"""
|
|
|
|
pass
|
2015-12-25 07:07:00 +11:00
|
|
|
|
2016-02-21 10:21:39 +11:00
|
|
|
def onPlayBackResumed(self):
|
2018-01-22 04:31:49 +11:00
|
|
|
"""
|
|
|
|
Will be called when playback is resumed
|
|
|
|
"""
|
|
|
|
pass
|
2015-12-25 07:07:00 +11:00
|
|
|
|
2016-02-21 10:21:39 +11:00
|
|
|
def onPlayBackSeek(self, time, seekOffset):
|
2018-01-22 04:31:49 +11:00
|
|
|
"""
|
|
|
|
Will be called when user seeks to a certain time during playback
|
|
|
|
"""
|
|
|
|
pass
|
2016-06-01 03:02:11 +10:00
|
|
|
|
2016-02-21 10:21:39 +11:00
|
|
|
def onPlayBackStopped(self):
|
2018-01-22 04:31:49 +11:00
|
|
|
"""
|
|
|
|
Will be called when playback is stopped by the user
|
|
|
|
"""
|
2018-02-04 00:05:18 +11:00
|
|
|
LOG.debug("ONPLAYBACK_STOPPED")
|
2018-02-07 23:57:07 +11:00
|
|
|
if state.PKC_CAUSED_STOP is True:
|
|
|
|
state.PKC_CAUSED_STOP = False
|
|
|
|
LOG.debug('PKC caused this playback stop - ignoring')
|
|
|
|
else:
|
|
|
|
playback_cleanup()
|
2016-03-17 04:01:07 +11:00
|
|
|
|
2018-01-22 04:31:49 +11:00
|
|
|
def onPlayBackEnded(self):
|
|
|
|
"""
|
|
|
|
Will be called when playback ends due to the media file being finished
|
|
|
|
"""
|
2018-02-04 00:05:18 +11:00
|
|
|
LOG.debug("ONPLAYBACK_ENDED")
|
2018-03-15 20:40:15 +11:00
|
|
|
playback_cleanup(ended=True)
|