jellyfin-kodi/resources/lib/kodimonitor.py

262 lines
9.4 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
2016-11-02 04:11:04 +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)
2016-11-02 04:11:04 +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():
item = xbmc.Player().getVideoInfoTag()
kodi_id = item.getDbId()
item_type = item.getMediaType()
if kodi_id is None or int(kodi_id) == -1:
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) == "true":
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') != 0:
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
xbmc.getInfoLabel('Control.GetLabel(1002)') == 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:
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