Merge pull request #913 from croneter/fix-timezones
Fix PKC potentially marking a video as watched on startup; don't sync time by toggling a video watch status but use PMS epoch time
This commit is contained in:
commit
fb4de9fb92
6 changed files with 6 additions and 128 deletions
|
@ -2,7 +2,6 @@
|
||||||
from __future__ import absolute_import, division, unicode_literals
|
from __future__ import absolute_import, division, unicode_literals
|
||||||
|
|
||||||
from .full_sync import start
|
from .full_sync import start
|
||||||
from .time import sync_pms_time
|
|
||||||
from .websocket import store_websocket_message, process_websocket_messages, \
|
from .websocket import store_websocket_message, process_websocket_messages, \
|
||||||
WEBSOCKET_MESSAGES, PLAYSTATE_SESSIONS
|
WEBSOCKET_MESSAGES, PLAYSTATE_SESSIONS
|
||||||
from .common import update_kodi_library, PLAYLIST_SYNC_ENABLED
|
from .common import update_kodi_library, PLAYLIST_SYNC_ENABLED
|
||||||
|
|
|
@ -1,104 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
from __future__ import absolute_import, division, unicode_literals
|
|
||||||
from logging import getLogger
|
|
||||||
|
|
||||||
from .. import plex_functions as PF, utils, timing, variables as v, app
|
|
||||||
|
|
||||||
LOG = getLogger('PLEX.sync.time')
|
|
||||||
|
|
||||||
|
|
||||||
def sync_pms_time():
|
|
||||||
"""
|
|
||||||
PMS does not provide a means to get a server timestamp. This is a work-
|
|
||||||
around - because the PMS might be in another time zone
|
|
||||||
|
|
||||||
In general, everything saved to Kodi shall be in Kodi time.
|
|
||||||
|
|
||||||
Any info with a PMS timestamp is in Plex time, naturally
|
|
||||||
"""
|
|
||||||
LOG.info('Synching time with PMS server')
|
|
||||||
# Find a PMS item where we can toggle the view state to enforce a
|
|
||||||
# change in lastViewedAt
|
|
||||||
|
|
||||||
# Get all Plex libraries
|
|
||||||
sections = PF.get_plex_sections()
|
|
||||||
if sections is None:
|
|
||||||
LOG.error("Error download PMS views, abort sync_pms_time")
|
|
||||||
return False
|
|
||||||
|
|
||||||
plex_id = None
|
|
||||||
typus = (
|
|
||||||
(v.PLEX_TYPE_MOVIE, v.PLEX_TYPE_MOVIE,),
|
|
||||||
(v.PLEX_TYPE_SHOW, v.PLEX_TYPE_EPISODE),
|
|
||||||
(v.PLEX_TYPE_ARTIST, v.PLEX_TYPE_SONG)
|
|
||||||
)
|
|
||||||
for section_type, plex_type in typus:
|
|
||||||
if plex_id:
|
|
||||||
break
|
|
||||||
for section in sections:
|
|
||||||
if plex_id:
|
|
||||||
break
|
|
||||||
if not section.attrib['type'] == section_type:
|
|
||||||
continue
|
|
||||||
library_id = section.attrib['key']
|
|
||||||
try:
|
|
||||||
iterator = PF.SectionItems(library_id, plex_type=plex_type)
|
|
||||||
for item in iterator:
|
|
||||||
if item.get('viewCount'):
|
|
||||||
# Don't want to mess with items that have playcount>0
|
|
||||||
continue
|
|
||||||
if item.get('viewOffset'):
|
|
||||||
# Don't mess with items with a resume point
|
|
||||||
continue
|
|
||||||
plex_id = utils.cast(int, item.get('ratingKey'))
|
|
||||||
LOG.info('Found a %s item to sync with: %s',
|
|
||||||
plex_type, plex_id)
|
|
||||||
break
|
|
||||||
except RuntimeError:
|
|
||||||
pass
|
|
||||||
if plex_id is None:
|
|
||||||
LOG.error("Could not find an item to sync time with")
|
|
||||||
LOG.error("Aborting PMS-Kodi time sync")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Get the Plex item's metadata
|
|
||||||
xml = PF.GetPlexMetadata(plex_id)
|
|
||||||
if xml in (None, 401):
|
|
||||||
LOG.error("Could not download metadata, aborting time sync")
|
|
||||||
return False
|
|
||||||
|
|
||||||
timestamp = xml[0].get('lastViewedAt')
|
|
||||||
if timestamp is None:
|
|
||||||
timestamp = xml[0].get('updatedAt')
|
|
||||||
LOG.debug('Using items updatedAt=%s', timestamp)
|
|
||||||
if timestamp is None:
|
|
||||||
timestamp = xml[0].get('addedAt')
|
|
||||||
LOG.debug('Using items addedAt=%s', timestamp)
|
|
||||||
if timestamp is None:
|
|
||||||
timestamp = 0
|
|
||||||
LOG.debug('No timestamp; using 0')
|
|
||||||
timestamp = utils.cast(int, timestamp)
|
|
||||||
# Set the timer
|
|
||||||
koditime = timing.unix_timestamp()
|
|
||||||
# Toggle watched state
|
|
||||||
PF.scrobble(plex_id, 'watched')
|
|
||||||
# Let the PMS process this first!
|
|
||||||
app.APP.monitor.waitForAbort(1)
|
|
||||||
# Get updated metadata
|
|
||||||
xml = PF.GetPlexMetadata(plex_id)
|
|
||||||
# Toggle watched state back
|
|
||||||
PF.scrobble(plex_id, 'unwatched')
|
|
||||||
try:
|
|
||||||
plextime = xml[0].attrib['lastViewedAt']
|
|
||||||
except (IndexError, TypeError, AttributeError, KeyError):
|
|
||||||
LOG.warn('Could not get lastViewedAt - aborting')
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Calculate time offset Kodi-PMS
|
|
||||||
timing.KODI_PLEX_TIME_OFFSET = float(koditime) - float(plextime)
|
|
||||||
utils.settings('kodiplextimeoffset',
|
|
||||||
value=str(timing.KODI_PLEX_TIME_OFFSET))
|
|
||||||
LOG.info("Time offset Koditime - Plextime in seconds: %s",
|
|
||||||
timing.KODI_PLEX_TIME_OFFSET)
|
|
||||||
return True
|
|
|
@ -87,8 +87,6 @@ class Service(object):
|
||||||
utils.window(prop, clear=True)
|
utils.window(prop, clear=True)
|
||||||
|
|
||||||
clientinfo.getDeviceId()
|
clientinfo.getDeviceId()
|
||||||
# Init time-offset between Kodi and Plex
|
|
||||||
timing.KODI_PLEX_TIME_OFFSET = float(utils.settings('kodiplextimeoffset') or 0.0)
|
|
||||||
|
|
||||||
self.startup_completed = False
|
self.startup_completed = False
|
||||||
self.server_has_been_online = True
|
self.server_has_been_online = True
|
||||||
|
|
|
@ -137,7 +137,6 @@ class Sync(backgroundthread.KillableThread):
|
||||||
playlist_monitor = None
|
playlist_monitor = None
|
||||||
initial_sync_done = False
|
initial_sync_done = False
|
||||||
last_websocket_processing = 0
|
last_websocket_processing = 0
|
||||||
last_time_sync = 0
|
|
||||||
one_day_in_seconds = 60 * 60 * 24
|
one_day_in_seconds = 60 * 60 * 24
|
||||||
# Link to Websocket queue
|
# Link to Websocket queue
|
||||||
queue = app.APP.websocket_queue
|
queue = app.APP.websocket_queue
|
||||||
|
@ -171,8 +170,6 @@ class Sync(backgroundthread.KillableThread):
|
||||||
return
|
return
|
||||||
if not install_sync_done:
|
if not install_sync_done:
|
||||||
# Very FIRST sync ever upon installation or reset of Kodi DB
|
# Very FIRST sync ever upon installation or reset of Kodi DB
|
||||||
# Initialize time offset Kodi - PMS
|
|
||||||
library_sync.sync_pms_time()
|
|
||||||
last_time_sync = timing.unix_timestamp()
|
last_time_sync = timing.unix_timestamp()
|
||||||
LOG.info('Initial start-up full sync starting')
|
LOG.info('Initial start-up full sync starting')
|
||||||
xbmc.executebuiltin('InhibitIdleShutdown(true)')
|
xbmc.executebuiltin('InhibitIdleShutdown(true)')
|
||||||
|
@ -227,10 +224,6 @@ class Sync(backgroundthread.KillableThread):
|
||||||
not app.APP.is_playing_video):
|
not app.APP.is_playing_video):
|
||||||
LOG.info('Doing scheduled full library scan')
|
LOG.info('Doing scheduled full library scan')
|
||||||
self.start_library_sync()
|
self.start_library_sync()
|
||||||
elif now - last_time_sync > one_day_in_seconds:
|
|
||||||
LOG.info('Starting daily time sync')
|
|
||||||
library_sync.sync_pms_time()
|
|
||||||
last_time_sync = now
|
|
||||||
elif not app.SYNC.background_sync_disabled:
|
elif not app.SYNC.background_sync_disabled:
|
||||||
# Check back whether we should process something Only do
|
# Check back whether we should process something Only do
|
||||||
# this once a while (otherwise, potentially many screen
|
# this once a while (otherwise, potentially many screen
|
||||||
|
|
|
@ -6,9 +6,6 @@ from time import localtime, strftime
|
||||||
|
|
||||||
EPOCH = datetime.utcfromtimestamp(0)
|
EPOCH = datetime.utcfromtimestamp(0)
|
||||||
|
|
||||||
# What's the time offset between the PMS and Kodi?
|
|
||||||
KODI_PLEX_TIME_OFFSET = 0.0
|
|
||||||
|
|
||||||
|
|
||||||
def unix_timestamp(seconds_into_the_future=None):
|
def unix_timestamp(seconds_into_the_future=None):
|
||||||
"""
|
"""
|
||||||
|
@ -37,27 +34,23 @@ def unix_date_to_kodi(unix_kodi_time):
|
||||||
|
|
||||||
def plex_date_to_kodi(plex_timestamp):
|
def plex_date_to_kodi(plex_timestamp):
|
||||||
"""
|
"""
|
||||||
converts a Unix time stamp (seconds passed sinceJanuary 1 1970) to a
|
converts a PMS epoch time stamp (seconds passed since January 1 1970, Plex
|
||||||
propper, human-readable time stamp used by Kodi
|
sends timezone-independent epoch) to a propper, human-readable time stamp
|
||||||
|
used by Kodi (varies per time-zone!)
|
||||||
|
|
||||||
Output: Y-m-d h:m:s = 2009-04-05 23:16:04
|
Output: Y-m-d h:m:s = 2009-04-05 23:16:04
|
||||||
|
|
||||||
Returns None if plex_timestamp is not valid (e.g. -1))
|
Returns None if plex_timestamp is not valid (e.g. -1))
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return strftime('%Y-%m-%d %H:%M:%S',
|
return unix_date_to_kodi(plex_timestamp)
|
||||||
localtime(float(plex_timestamp) + KODI_PLEX_TIME_OFFSET))
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
# the PMS can return -1 as plex_timestamp - great!
|
# the PMS can return -1 as plex_timestamp - great!
|
||||||
return
|
pass
|
||||||
|
|
||||||
|
|
||||||
def kodi_date_to_plex(kodi_timestamp):
|
|
||||||
return float(kodi_timestamp) - KODI_PLEX_TIME_OFFSET
|
|
||||||
|
|
||||||
|
|
||||||
def plex_now():
|
def plex_now():
|
||||||
return kodi_date_to_plex(unix_timestamp())
|
return unix_timestamp()
|
||||||
|
|
||||||
|
|
||||||
def kodi_timestamp(plex_timestamp):
|
def kodi_timestamp(plex_timestamp):
|
||||||
|
|
|
@ -82,7 +82,6 @@
|
||||||
<setting label="[COLOR yellow]$ADDON[plugin.video.plexkodiconnect 30517][/COLOR]" type="action" action="RunPlugin(plugin://plugin.video.plexkodiconnect?mode=passwords)" option="close" /><!-- Set network credentials for Direct Paths and direct play -->
|
<setting label="[COLOR yellow]$ADDON[plugin.video.plexkodiconnect 30517][/COLOR]" type="action" action="RunPlugin(plugin://plugin.video.plexkodiconnect?mode=passwords)" option="close" /><!-- Set network credentials for Direct Paths and direct play -->
|
||||||
|
|
||||||
<setting id="streamMusic" type="bool" label="30510" default="false" visible="false" subsetting="true"/> <!-- Direct stream Music library -->
|
<setting id="streamMusic" type="bool" label="30510" default="false" visible="false" subsetting="true"/> <!-- Direct stream Music library -->
|
||||||
<setting id="kodiplextimeoffset" type="number" label="Time difference in seconds (Koditime - Plextime)" default="0" visible="false" option="int" />
|
|
||||||
<setting id="themoviedbAPIKey" type="text" default="19c90103adb9e98f2172c6a6a3d85dc4" visible="false"/>
|
<setting id="themoviedbAPIKey" type="text" default="19c90103adb9e98f2172c6a6a3d85dc4" visible="false"/>
|
||||||
<setting id="FanArtTVAPIKey" type="text" default="639191cb0774661597f28a47e7e2bad5" visible="false"/>
|
<setting id="FanArtTVAPIKey" type="text" default="639191cb0774661597f28a47e7e2bad5" visible="false"/>
|
||||||
<setting id="syncEmptyShows" type="bool" label="30508" default="false" visible="false"/>
|
<setting id="syncEmptyShows" type="bool" label="30508" default="false" visible="false"/>
|
||||||
|
|
Loading…
Reference in a new issue