2015-03-13 21:24:59 +00:00
import xbmcaddon
import xbmcplugin
import xbmc
import xbmcgui
import os
import threading
import json
2015-03-20 20:00:17 +00:00
import inspect
2015-03-13 21:24:59 +00:00
import KodiMonitor
import Utils as utils
from DownloadUtils import DownloadUtils
from PlayUtils import PlayUtils
from ClientInformation import ClientInformation
from LibrarySync import LibrarySync
2015-03-28 01:34:09 +00:00
from PlaybackUtils import PlaybackUtils
2015-04-07 14:21:54 +00:00
from ReadEmbyDB import ReadEmbyDB
from API import API
2015-03-13 21:24:59 +00:00
librarySync = LibrarySync ( )
# service class for playback monitoring
class Player ( xbmc . Player ) :
logLevel = 0
played_information = { }
downloadUtils = None
settings = None
playStats = { }
def __init__ ( self , * args ) :
2015-03-25 17:37:21 +00:00
self . settings = xbmcaddon . Addon ( id = ' plugin.video.emby ' )
2015-03-13 21:24:59 +00:00
self . downloadUtils = DownloadUtils ( )
try :
self . logLevel = int ( self . settings . getSetting ( ' logLevel ' ) )
except :
pass
2015-03-25 17:37:21 +00:00
self . printDebug ( " emby Service -> starting playback monitor service " , 1 )
2015-03-13 21:24:59 +00:00
self . played_information = { }
pass
def printDebug ( self , msg , level = 1 ) :
if ( self . logLevel > = level ) :
if ( self . logLevel == 2 ) :
try :
2015-03-25 17:37:21 +00:00
xbmc . log ( " emby " + str ( level ) + " -> " + inspect . stack ( ) [ 1 ] [ 3 ] + " : " + str ( msg ) )
2015-03-13 21:24:59 +00:00
except UnicodeEncodeError :
2015-03-25 17:37:21 +00:00
xbmc . log ( " emby " + str ( level ) + " -> " + inspect . stack ( ) [ 1 ] [ 3 ] + " : " + str ( msg . encode ( ' utf-8 ' ) ) )
2015-03-13 21:24:59 +00:00
else :
try :
2015-03-25 17:37:21 +00:00
xbmc . log ( " emby " + str ( level ) + " -> " + str ( msg ) )
2015-03-13 21:24:59 +00:00
except UnicodeEncodeError :
2015-03-25 17:37:21 +00:00
xbmc . log ( " emby " + str ( level ) + " -> " + str ( msg . encode ( ' utf-8 ' ) ) )
2015-03-13 21:24:59 +00:00
def hasData ( self , data ) :
if ( data == None or len ( data ) == 0 or data == " None " ) :
return False
else :
return True
def stopAll ( self ) :
if ( len ( self . played_information ) == 0 ) :
return
2015-03-25 17:37:21 +00:00
addonSettings = xbmcaddon . Addon ( id = ' plugin.video.emby ' )
self . printDebug ( " emby Service -> played_information : " + str ( self . played_information ) )
2015-03-13 21:24:59 +00:00
for item_url in self . played_information :
data = self . played_information . get ( item_url )
if ( data != None ) :
2015-03-25 17:37:21 +00:00
self . printDebug ( " emby Service -> item_url : " + item_url )
self . printDebug ( " emby Service -> item_data : " + str ( data ) )
2015-03-13 21:24:59 +00:00
runtime = data . get ( " runtime " )
currentPosition = data . get ( " currentPosition " )
item_id = data . get ( " item_id " )
refresh_id = data . get ( " refresh_id " )
currentFile = data . get ( " currentfile " )
2015-03-19 17:40:29 +00:00
type = data . get ( " Type " )
2015-03-23 05:24:52 +00:00
2015-03-13 21:24:59 +00:00
if ( currentPosition != None and self . hasData ( runtime ) ) :
runtimeTicks = int ( runtime )
2015-03-25 17:37:21 +00:00
self . printDebug ( " emby Service -> runtimeticks: " + str ( runtimeTicks ) )
2015-03-13 21:24:59 +00:00
percentComplete = ( currentPosition * 10000000 ) / runtimeTicks
markPlayedAt = float ( 90 ) / 100
2015-03-25 17:37:21 +00:00
self . printDebug ( " emby Service -> Percent Complete: " + str ( percentComplete ) + " Mark Played At: " + str ( markPlayedAt ) )
2015-03-13 21:24:59 +00:00
self . stopPlayback ( data )
2015-03-22 03:19:26 +00:00
if ( refresh_id != None ) :
#report updates playcount and resume status to Kodi and MB3
2015-04-18 02:28:39 +00:00
librarySync . updatePlayCount ( item_id )
2015-04-07 14:21:54 +00:00
2015-03-13 21:24:59 +00:00
self . played_information . clear ( )
2015-04-13 18:56:36 +00:00
WINDOW = xbmcgui . Window ( 10000 )
username = WINDOW . getProperty ( ' currUser ' )
server = WINDOW . getProperty ( ' server %s ' % username )
2015-03-13 21:24:59 +00:00
# stop transcoding - todo check we are actually transcoding?
clientInfo = ClientInformation ( )
txt_mac = clientInfo . getMachineId ( )
2015-04-13 18:56:36 +00:00
url = " %s /mediabrowser/Videos/ActiveEncodings " % server
2015-03-13 21:24:59 +00:00
url = url + ' ?DeviceId= ' + txt_mac
2015-03-22 03:19:26 +00:00
self . downloadUtils . downloadUrl ( url , type = " DELETE " )
2015-03-13 21:24:59 +00:00
def stopPlayback ( self , data ) :
2015-03-23 05:24:52 +00:00
self . printDebug ( " stopPlayback called " )
2015-03-25 17:37:21 +00:00
addonSettings = xbmcaddon . Addon ( id = ' plugin.video.emby ' )
2015-03-13 21:24:59 +00:00
item_id = data . get ( " item_id " )
audioindex = data . get ( " AudioStreamIndex " )
subtitleindex = data . get ( " SubtitleStreamIndex " )
playMethod = data . get ( " playmethod " )
currentPosition = data . get ( " currentPosition " )
positionTicks = str ( int ( currentPosition * 10000000 ) )
2015-04-13 18:56:36 +00:00
WINDOW = xbmcgui . Window ( 10000 )
username = WINDOW . getProperty ( ' currUser ' )
server = WINDOW . getProperty ( ' server %s ' % username )
url = " %s /mediabrowser/Sessions/Playing/Stopped " % server
2015-03-13 21:24:59 +00:00
url = url + " ?itemId= " + item_id
url = url + " &canSeek=true "
url = url + " &PlayMethod= " + playMethod
url = url + " &QueueableMediaTypes=Video "
url = url + " &MediaSourceId= " + item_id
url = url + " &PositionTicks= " + positionTicks
if ( audioindex != None and audioindex != " " ) :
url = url + " &AudioStreamIndex= " + audioindex
if ( subtitleindex != None and subtitleindex != " " ) :
url = url + " &SubtitleStreamIndex= " + subtitleindex
self . downloadUtils . downloadUrl ( url , postBody = " " , type = " POST " )
def reportPlayback ( self ) :
2015-03-19 23:34:56 +00:00
self . printDebug ( " reportPlayback Called " , 2 )
2015-03-13 21:24:59 +00:00
currentFile = xbmc . Player ( ) . getPlayingFile ( )
#TODO need to change this to use the one in the data map
playTime = xbmc . Player ( ) . getTime ( )
data = self . played_information . get ( currentFile )
2015-03-25 17:37:21 +00:00
# only report playback if emby has initiated the playback (item_id has value)
2015-03-13 21:24:59 +00:00
if ( data != None and data . get ( " item_id " ) != None ) :
2015-03-25 17:37:21 +00:00
addonSettings = xbmcaddon . Addon ( id = ' plugin.video.emby ' )
2015-03-13 21:24:59 +00:00
item_id = data . get ( " item_id " )
audioindex = data . get ( " AudioStreamIndex " )
subtitleindex = data . get ( " SubtitleStreamIndex " )
playMethod = data . get ( " playmethod " )
paused = data . get ( " paused " )
2015-04-13 18:56:36 +00:00
WINDOW = xbmcgui . Window ( 10000 )
username = WINDOW . getProperty ( ' currUser ' )
server = WINDOW . getProperty ( ' server %s ' % username )
2015-03-13 21:24:59 +00:00
2015-04-13 18:56:36 +00:00
url = " %s /mediabrowser/Sessions/Playing/Progress " % server
2015-03-13 21:24:59 +00:00
url = url + " ?itemId= " + item_id
url = url + " &canSeek=true "
url = url + " &PlayMethod= " + playMethod
url = url + " &QueueableMediaTypes=Video "
url = url + " &MediaSourceId= " + item_id
url = url + " &PositionTicks= " + str ( int ( playTime * 10000000 ) )
if ( audioindex != None and audioindex != " " ) :
url = url + " &AudioStreamIndex= " + audioindex
if ( subtitleindex != None and subtitleindex != " " ) :
url = url + " &SubtitleStreamIndex= " + subtitleindex
if ( paused == None ) :
paused = " false "
url = url + " &IsPaused= " + paused
self . downloadUtils . downloadUrl ( url , postBody = " " , type = " POST " )
def onPlayBackPaused ( self ) :
currentFile = xbmc . Player ( ) . getPlayingFile ( )
2015-03-19 23:34:56 +00:00
self . printDebug ( " PLAYBACK_PAUSED : " + currentFile , 2 )
2015-03-13 21:24:59 +00:00
if ( self . played_information . get ( currentFile ) != None ) :
self . played_information [ currentFile ] [ " paused " ] = " true "
self . reportPlayback ( )
def onPlayBackResumed ( self ) :
currentFile = xbmc . Player ( ) . getPlayingFile ( )
2015-03-19 23:34:56 +00:00
self . printDebug ( " PLAYBACK_RESUMED : " + currentFile , 2 )
2015-03-13 21:24:59 +00:00
if ( self . played_information . get ( currentFile ) != None ) :
self . played_information [ currentFile ] [ " paused " ] = " false "
self . reportPlayback ( )
def onPlayBackSeek ( self , time , seekOffset ) :
2015-03-19 23:34:56 +00:00
self . printDebug ( " PLAYBACK_SEEK " , 2 )
2015-03-13 21:24:59 +00:00
self . reportPlayback ( )
def onPlayBackStarted ( self ) :
# Will be called when xbmc starts playing a file
WINDOW = xbmcgui . Window ( 10000 )
self . stopAll ( )
2015-03-25 17:37:21 +00:00
addonSettings = xbmcaddon . Addon ( id = ' plugin.video.emby ' )
2015-03-22 13:02:38 +00:00
xbmcplayer = xbmc . Player ( )
2015-03-13 21:24:59 +00:00
2015-03-22 13:02:38 +00:00
if xbmcplayer . isPlaying ( ) :
currentFile = xbmcplayer . getPlayingFile ( )
2015-03-30 10:01:26 +00:00
self . printDebug ( " emby Service -> onPlayBackStarted : " + currentFile , 0 )
# we may need to wait until the info is available
item_id = WINDOW . getProperty ( currentFile + " item_id " )
tryCount = 0
while ( item_id == None or item_id == " " ) :
xbmc . sleep ( 500 )
item_id = WINDOW . getProperty ( currentFile + " item_id " )
tryCount + = 1
if ( tryCount == 20 ) : # try 20 times or about 10 seconds
return
xbmc . sleep ( 500 )
2015-03-13 21:24:59 +00:00
# grab all the info about this item from the stored windows props
# only ever use the win props here, use the data map in all other places
runtime = WINDOW . getProperty ( currentFile + " runtimeticks " )
refresh_id = WINDOW . getProperty ( currentFile + " refresh_id " )
audioindex = WINDOW . getProperty ( currentFile + " AudioStreamIndex " )
subtitleindex = WINDOW . getProperty ( currentFile + " SubtitleStreamIndex " )
playMethod = WINDOW . getProperty ( currentFile + " playmethod " )
itemType = WINDOW . getProperty ( currentFile + " type " )
seekTime = WINDOW . getProperty ( currentFile + " seektime " )
if seekTime != " " :
2015-03-28 01:34:09 +00:00
PlaybackUtils ( ) . seekToPosition ( int ( seekTime ) )
2015-03-13 21:24:59 +00:00
if ( item_id == None or len ( item_id ) == 0 ) :
2015-03-30 10:01:26 +00:00
self . printDebug ( " emby Service -> onPlayBackStarted : No info for current playing file " , 0 )
2015-03-13 21:24:59 +00:00
return
2015-04-13 18:56:36 +00:00
username = WINDOW . getProperty ( ' currUser ' )
server = WINDOW . getProperty ( ' server %s ' % username )
url = " %s /mediabrowser/Sessions/Playing " % server
2015-03-13 21:24:59 +00:00
url = url + " ?itemId= " + item_id
url = url + " &canSeek=true "
url = url + " &PlayMethod= " + playMethod
url = url + " &QueueableMediaTypes=Video "
url = url + " &MediaSourceId= " + item_id
if ( audioindex != None and audioindex != " " ) :
url = url + " &AudioStreamIndex= " + audioindex
if ( subtitleindex != None and subtitleindex != " " ) :
url = url + " &SubtitleStreamIndex= " + subtitleindex
2015-03-30 10:01:26 +00:00
self . printDebug ( " emby Service -> Sending Post Play Started : " + url , 0 )
2015-03-22 12:22:09 +00:00
self . downloadUtils . downloadUrl ( url , postBody = " " , type = " POST " )
2015-03-22 03:19:26 +00:00
2015-03-13 21:24:59 +00:00
# save data map for updates and position calls
data = { }
data [ " runtime " ] = runtime
data [ " item_id " ] = item_id
data [ " refresh_id " ] = refresh_id
2015-03-23 05:24:52 +00:00
data [ " currentfile " ] = currentFile
2015-03-13 21:24:59 +00:00
data [ " AudioStreamIndex " ] = audioindex
data [ " SubtitleStreamIndex " ] = subtitleindex
data [ " playmethod " ] = playMethod
data [ " Type " ] = itemType
2015-03-23 05:24:52 +00:00
self . played_information [ currentFile ] = data
2015-03-13 21:24:59 +00:00
2015-03-30 10:01:26 +00:00
self . printDebug ( " emby Service -> ADDING_FILE : " + currentFile , 0 )
self . printDebug ( " emby Service -> ADDING_FILE : " + str ( self . played_information ) , 0 )
2015-03-13 21:24:59 +00:00
# log some playback stats
if ( itemType != None ) :
if ( self . playStats . get ( itemType ) != None ) :
count = self . playStats . get ( itemType ) + 1
self . playStats [ itemType ] = count
else :
self . playStats [ itemType ] = 1
if ( playMethod != None ) :
if ( self . playStats . get ( playMethod ) != None ) :
count = self . playStats . get ( playMethod ) + 1
self . playStats [ playMethod ] = count
else :
self . playStats [ playMethod ] = 1
# reset in progress position
self . reportPlayback ( )
def GetPlayStats ( self ) :
return self . playStats
def onPlayBackEnded ( self ) :
# Will be called when xbmc stops playing a file
2015-03-25 17:37:21 +00:00
self . printDebug ( " emby Service -> onPlayBackEnded " )
2015-03-22 03:19:26 +00:00
#workaround when strm files are launched through the addon - mark watched when finished playing
#TODO --> mark watched when 95% is played of the file
WINDOW = xbmcgui . Window ( 10000 )
if WINDOW . getProperty ( " virtualstrm " ) != " " :
try :
id = WINDOW . getProperty ( " virtualstrm " )
type = WINDOW . getProperty ( " virtualstrmtype " )
2015-03-25 17:37:21 +00:00
addon = xbmcaddon . Addon ( id = ' plugin.video.emby ' )
2015-04-13 18:56:36 +00:00
username = WINDOW . getProperty ( ' currUser ' )
userid = WINDOW . getProperty ( ' userId %s ' % username )
server = WINDOW . getProperty ( ' server %s ' % username )
watchedurl = " %s /mediabrowser/Users/ %s /PlayedItems/ %s " % ( server , userid , id )
2015-03-22 03:19:26 +00:00
self . downloadUtils . downloadUrl ( watchedurl , postBody = " " , type = " POST " )
2015-04-18 02:28:39 +00:00
librarySync . updatePlayCount ( id )
2015-03-22 03:19:26 +00:00
except : pass
WINDOW . clearProperty ( " virtualstrm " )
2015-03-13 21:24:59 +00:00
self . stopAll ( )
def onPlayBackStopped ( self ) :
# Will be called when user stops xbmc playing a file
2015-03-25 17:37:21 +00:00
self . printDebug ( " emby Service -> onPlayBackStopped " )
2015-03-13 21:24:59 +00:00
self . stopAll ( )
2015-04-09 12:29:48 +00:00
def autoPlayPlayback ( self ) :
currentFile = xbmc . Player ( ) . getPlayingFile ( )
data = self . played_information . get ( currentFile )
# only report playback if emby has initiated the playback (item_id has value)
if ( data != None and data . get ( " item_id " ) != None ) :
addonSettings = xbmcaddon . Addon ( id = ' plugin.video.emby ' )
item_id = data . get ( " item_id " )
type = data . get ( " Type " )
# if its an episode see if autoplay is enabled
if addonSettings . getSetting ( " autoPlaySeason " ) == " true " and type == " Episode " :
2015-04-13 18:56:36 +00:00
WINDOW = xbmcgui . Window ( 10000 )
username = WINDOW . getProperty ( ' currUser ' )
userid = WINDOW . getProperty ( ' userId %s ' % username )
server = WINDOW . getProperty ( ' server %s ' % username )
2015-04-09 12:29:48 +00:00
# add remaining unplayed episodes if applicable
MB3Episode = ReadEmbyDB ( ) . getItem ( item_id )
userData = MB3Episode [ " UserData " ]
if userData != None and userData [ " Played " ] == True :
pDialog = xbmcgui . DialogProgress ( )
seasonId = MB3Episode [ " SeasonId " ]
2015-04-13 18:56:36 +00:00
url = " %s /mediabrowser/Users/ %s /Items?ParentId= %s &ImageTypeLimit=1&Limit=1&SortBy=SortName&SortOrder=Ascending&Filters=IsUnPlayed&IncludeItemTypes=Episode&IsVirtualUnaired=false&Recursive=true&IsMissing=False&format=json " % ( server , userid , seasonId )
jsonData = self . downloadUtils . downloadUrl ( url , suppress = False , popup = 1 )
2015-04-09 12:29:48 +00:00
if ( jsonData != " " ) :
seasonData = json . loads ( jsonData )
if seasonData . get ( " Items " ) != None :
item = seasonData . get ( " Items " ) [ 0 ]
pDialog . create ( " Auto Play next episode " , str ( item . get ( " ParentIndexNumber " ) ) + " x " + str ( item . get ( " IndexNumber " ) ) + " . " + item [ " Name " ] + " found " , " Cancel to stop automatic play " )
count = 0
while ( pDialog . iscanceled ( ) == False and count < 10 ) :
xbmc . sleep ( 1000 )
count + = 1
progress = count * 10
remainingsecs = 10 - count
pDialog . update ( progress , str ( item . get ( " ParentIndexNumber " ) ) + " x " + str ( item . get ( " IndexNumber " ) ) + " . " + item [ " Name " ] + " found " , " Cancel to stop automatic play " , str ( remainingsecs ) + " second(s) until auto dismiss " )
pDialog . close ( )
if pDialog . iscanceled ( ) == False :
playTime = xbmc . Player ( ) . getTime ( )
totalTime = xbmc . Player ( ) . getTotalTime ( )
while xbmc . Player ( ) . isPlaying ( ) and ( totalTime - playTime > 2 ) :
xbmc . sleep ( 500 )
playTime = xbmc . Player ( ) . getTime ( )
totalTime = xbmc . Player ( ) . getTotalTime ( )
2015-04-13 18:56:36 +00:00
PlaybackUtils ( ) . PLAYAllEpisodes ( seasonData . get ( " Items " ) )