jellyfin-kodi/resources/lib/kodimonitor.py

267 lines
9.8 KiB
Python
Raw Normal View History

2016-03-31 15:39:00 +00:00
# -*- coding: utf-8 -*-
#################################################################################################
import json
import logging
import threading
2016-03-31 15:39:00 +00:00
import xbmc
import xbmcgui
import downloadutils
import embydb_functions as embydb
import playbackutils as pbutils
from utils import window, settings, create_id
2018-05-13 03:56:53 +00:00
#from ga_client import log_error
2016-11-05 02:19:57 +00:00
from database import DatabaseConn
#################################################################################################
log = logging.getLogger("EMBY."+__name__)
2017-03-27 16:31:26 +00:00
KODI = int(xbmc.getInfoLabel('System.BuildVersion')[:2])
2016-03-31 15:39:00 +00:00
#################################################################################################
class KodiMonitor(xbmc.Monitor):
2017-11-03 03:34:55 +00:00
retry = True
special_monitor = None
2016-03-31 15:39:00 +00:00
def __init__(self):
2016-09-27 02:50:58 +00:00
xbmc.Monitor.__init__(self)
2018-01-09 11:42:37 +00:00
self.special_monitor = SpecialMonitor().start()
2016-09-10 11:15:58 +00:00
self.download = downloadutils.DownloadUtils().downloadUrl
log.info("Kodi monitor started")
2016-03-31 15:39:00 +00:00
def onScanStarted(self, library):
2016-09-10 11:15:58 +00:00
log.debug("Kodi library scan %s running", library)
2016-03-31 15:39:00 +00:00
if library == "video":
2016-06-18 03:03:28 +00:00
window('emby_kodiScan', value="true")
2016-09-10 11:15:58 +00:00
2016-03-31 15:39:00 +00:00
def onScanFinished(self, library):
2016-09-10 11:15:58 +00:00
log.info("Kodi library scan %s finished", library)
2016-03-31 15:39:00 +00:00
if library == "video":
2016-06-18 03:03:28 +00:00
window('emby_kodiScan', clear=True)
2016-03-31 15:39:00 +00:00
def onSettingsChanged(self):
# Monitor emby settings
2016-09-10 11:15:58 +00:00
current_log_level = settings('logLevel')
if window('emby_logLevel') != current_log_level:
2016-03-31 15:39:00 +00:00
# The log level changed, set new prop
2016-09-10 11:15:58 +00:00
log.info("New log level: %s", current_log_level)
window('emby_logLevel', value=current_log_level)
2016-03-31 15:39:00 +00:00
current_context = "true" if settings('enableContext') == "true" else ""
if window('emby_context') != current_context:
log.info("New context setting: %s", current_context)
window('emby_context', value=current_context)
current_context = "true" if settings('enableContextTranscode') == "true" else ""
if window('emby_context_transcode') != current_context:
log.info("New context transcode setting: %s", current_context)
window('emby_context_transcode', value=current_context)
2018-05-13 03:56:53 +00:00
#@log_error()
2016-03-31 15:39:00 +00:00
def onNotification(self, sender, method, data):
2016-09-10 11:15:58 +00:00
if method not in ('Playlist.OnAdd', 'Player.OnStop', 'Player.OnClear'):
log.info("Method: %s Data: %s", method, data)
try:
if data:
data = json.loads(data, 'utf-8')
except:
log.info("Error parsing message data: %s", data)
return
2016-09-10 11:15:58 +00:00
if method == 'Player.OnPlay':
self.retry = True
2016-09-10 11:15:58 +00:00
self._on_play_(data)
elif method == 'VideoLibrary.OnUpdate':
self._video_update(data)
elif method == 'System.OnSleep':
# Connection is going to sleep
log.info("Marking the server as offline. System.OnSleep activated.")
window('emby_online', value="sleep")
2016-03-31 15:39:00 +00:00
2016-09-10 11:15:58 +00:00
elif method == 'System.OnWake':
self._system_wake()
elif method == 'GUI.OnScreensaverDeactivated':
self._screensaver_deactivated()
def _on_play_(self, data):
# Set up report progress for emby playback
try:
kodi_id = None
2017-10-04 22:34:25 +00:00
if KODI >= 17 and xbmc.Player().isPlayingVideo():
2018-05-10 09:06:18 +00:00
''' Seems to misbehave when playback is not terminated prior to playing new content.
The kodi id remains that of the previous title. Maybe onPlay happens before
this information is updated. Added a failsafe further below.
'''
item = xbmc.Player().getVideoInfoTag()
kodi_id = item.getDbId()
item_type = item.getMediaType()
2018-05-15 07:10:57 +00:00
if kodi_id is None or int(kodi_id) == -1 or 'item' in data and 'id' in data['item'] and data['item']['id'] != kodi_id:
item = data['item']
kodi_id = item['id']
item_type = item['type']
log.info("kodi_id: %s item_type: %s", kodi_id, item_type)
2016-09-10 11:15:58 +00:00
except (KeyError, TypeError):
log.info("Item is invalid for playstate update")
2017-11-03 03:34:55 +00:00
# Retry once, sometimes xbmc.Player().isPlayingVideo() will return false when played from widget.
if self.retry:
self.retry = False
xbmc.sleep(200)
return self._on_play_(data)
2017-03-27 16:31:26 +00:00
else:
2016-09-10 11:15:58 +00:00
if ((settings('useDirectPaths') == "1" and not item_type == "song") or
(item_type == "song" and settings('enableMusic') == "true")):
2016-09-10 11:15:58 +00:00
# Set up properties for player
item_id = self._get_item_id(kodi_id, item_type)
if item_id:
url = "{server}/emby/Users/{UserId}/Items/%s?format=json" % item_id
result = self.download(url)
log.debug("Item: %s", result)
playurl = None
count = 0
while not playurl and count < 2:
try:
playurl = xbmc.Player().getPlayingFile()
except RuntimeError:
count += 1
xbmc.sleep(200)
else:
window('emby_%s.play.json' % playurl, {
2016-09-10 11:15:58 +00:00
'playmethod': "DirectStream" if item_type == "song" and settings('streamMusic') == "true" else "DirectPlay",
'playsession_id': str(create_id()).replace("-", "")
})
listitem = xbmcgui.ListItem()
pbutils.PlaybackUtils(result).set_properties(playurl, listitem)
2016-09-10 11:15:58 +00:00
def _video_update(self, data):
# Manually marking as watched/unwatched
try:
item = data['item']
kodi_id = item['id']
item_type = item['type']
except (KeyError, TypeError):
log.info("Item is invalid for playstate update")
else:
# Send notification to the server.
item_id = self._get_item_id(kodi_id, item_type)
if item_id:
# Stop from manually marking as watched unwatched, with actual playback.
if window('emby.skip.%s' % item_id):
2016-09-10 11:15:58 +00:00
# property is set in player.py
window('emby.skip.%s' % item_id, clear=True)
2016-09-10 11:15:58 +00:00
else:
# notify the server
url = "{server}/emby/Users/{UserId}/PlayedItems/%s?format=json" % item_id
if data.get('playcount'):
2016-09-10 11:15:58 +00:00
self.download(url, action_type="POST")
log.info("Mark as watched for itemid: %s", item_id)
else:
self.download(url, action_type="DELETE")
log.info("Mark as unwatched for itemid: %s", item_id)
@classmethod
def _system_wake(cls):
# Allow network to wake up
xbmc.sleep(10000)
window('emby_online', value="false")
window('emby_onWake', value="true")
@classmethod
def _screensaver_deactivated(cls):
if settings('dbSyncScreensaver') == "true":
xbmc.sleep(5000)
2016-06-18 03:03:28 +00:00
window('emby_onWake', value="true")
2016-03-31 15:39:00 +00:00
2016-09-10 11:15:58 +00:00
@classmethod
def _get_item_id(cls, kodi_id, item_type):
item_id = None
with DatabaseConn('emby') as cursor:
emby_db = embydb.Embydb_Functions(cursor)
db_item = emby_db.getItem_byKodiId(kodi_id, item_type)
2016-09-10 11:15:58 +00:00
try:
item_id = db_item[0]
except TypeError:
log.info("Could not retrieve item Id")
2016-09-10 11:15:58 +00:00
return item_id
class SpecialMonitor(threading.Thread):
_stop_thread = False
external_count = 0
def run(self):
''' Detect the resume dialog for widgets.
Detect external players.
'''
2018-01-09 11:42:37 +00:00
monitor = xbmc.Monitor()
log.warn("----====# Starting Special Monitor #====----")
while not self._stop_thread:
player = xbmc.Player()
isPlaying = player.isPlaying()
if (not isPlaying and xbmc.getCondVisibility('Window.IsVisible(DialogContextMenu.xml)') and
2018-05-10 09:06:18 +00:00
xbmc.getInfoLabel('Control.GetLabel(1002)').decode('utf-8') == xbmc.getLocalizedString(12021)):
control = int(xbmcgui.Window(10106).getFocusId())
if control == 1002: # Start from beginning
log.info("Resume dialog: Start from beginning selected.")
window('emby.resume', clear=True)
2018-03-23 10:17:28 +00:00
else:
2018-05-10 09:06:18 +00:00
log.info("Resume dialog: Resume selected.")
2018-03-23 10:17:28 +00:00
window('emby.resume', value="true")
elif isPlaying and not window('emby.external_check'):
time = player.getTime()
if time > 1: # Not external player.
window('emby.external_check', value="true")
self.external_count = 0
2018-04-04 03:28:01 +00:00
elif self.external_count == 120:
log.info("External player detected.")
window('emby.external', value="true")
window('emby.external_check', value="true")
self.external_count = 0
elif time == 0:
self.external_count += 1
if monitor.waitForAbort(0.5):
# Abort was requested while waiting. We should exit
break
log.warn("#====---- Special Monitor Stopped ----====#")
def stop_monitor(self):
self._stop_thread = True