diff --git a/addon.xml b/addon.xml
index 330ff55..102b63a 100644
--- a/addon.xml
+++ b/addon.xml
@@ -1,11 +1,11 @@
-
+
@@ -16,6 +16,6 @@
http://forum.kodi.tv/showthread.php?tid=211971
all
- GNU GENERAL PUBLIC LICENSE. Version 2, June 1991
+ GPL-2.0-only
diff --git a/resources/language/English/strings.po b/resources/language/English/strings.po
index e9b55bb..7ea95c7 100644
--- a/resources/language/English/strings.po
+++ b/resources/language/English/strings.po
@@ -16,116 +16,124 @@ msgstr ""
msgctxt "#30000"
msgid "Sleep Timer"
-""
+msgstr ""
msgctxt "#30001"
msgid "Cancel to continue playing"
-""
+msgstr ""
msgctxt "#30002"
msgid "Service check time (minutes)"
-""
+msgstr ""
msgctxt "#30003"
msgid "Waiting time for the dialog (before stop) (seconds)"
-""
+msgstr ""
msgctxt "#30004"
msgid "Slow mute audio before stop playing"
-""
+msgstr ""
msgctxt "#30005"
msgid "General"
-""
+msgstr ""
msgctxt "#30006"
-msgid "Time between 1% volume change (millisec)"
-""
+msgid "Time it takes to reach 0% volume (minutes)"
+msgstr ""
msgctxt "#30007"
msgid "Next check time if dialog is cancelled (minutes)"
-""
+msgstr ""
msgctxt "#30008"
msgid "Enable Screensaver after stopping"
-""
+msgstr ""
msgctxt "#30009"
msgid "Audio/Video Supervision settings"
-""
+msgstr ""
msgctxt "#30010"
msgid "Enable Video Supervision"
-""
+msgstr ""
msgctxt "#30011"
msgid "Enable Audio Supervision"
-""
+msgstr ""
msgctxt "#30012"
msgid "Maximum Playing time (minutes) before asking to stop"
-""
+msgstr ""
msgctxt "#30013"
msgid "Video Playbacktime"
-""
+msgstr ""
msgctxt "#30014"
msgid "Audio Playbacktime"
-""
+msgstr ""
msgctxt "#30015"
msgid "Debug"
-""
+msgstr ""
msgctxt "#30016"
-msgid "Debug mode"
-""
+msgid "Debug mode (overwrites some settings!)"
+msgstr ""
msgctxt "#30017"
msgid "'Enable' debugging sets:"
-""
+msgstr ""
msgctxt "#30018"
msgid "Audio and Video-Check enabled"
-""
+msgstr ""
msgctxt "#30019"
msgid "Service check time (minutes): '1'"
-""
+msgstr ""
msgctxt "#30020"
msgid "Waiting time for the dialog (before stop) (seconds): '30'"
-""
+msgstr ""
msgctxt "#30021"
msgid "It doesn't matter, what you set in the other Tabs!"
-""
+msgstr ""
msgctxt "#30022"
msgid "Execute custom cmd after playback stop"
-""
+msgstr ""
msgctxt "#30023"
msgid "Custom CMD"
-""
+msgstr ""
msgctxt "#30024"
msgid "Supervision Mode"
-""
+msgstr ""
msgctxt "#30025"
msgid "Hour start (eg. 23:00)"
-""
+msgstr ""
msgctxt "#30026"
msgid "Hour supervision end (eg. 03:20)"
-""
+msgstr ""
msgctxt "#30027"
msgid "Always"
-""
+msgstr ""
msgctxt "#30028"
msgid "Specific Time"
-""
\ No newline at end of file
+msgstr ""
+
+msgctxt "#30029"
+msgid "Set the minimum volume %"
+msgstr ""
+
+msgctxt "#30030"
+msgid "Alternative mode (user interaction is detected differently)"
+msgstr ""
diff --git a/resources/language/Portuguese/strings.po b/resources/language/Portuguese/strings.po
index 5828ff1..83957c5 100644
--- a/resources/language/Portuguese/strings.po
+++ b/resources/language/Portuguese/strings.po
@@ -38,8 +38,8 @@ msgid "General"
msgstr "Geral"
msgctxt "#30006"
-msgid "Time between 1% volume change (millisec)"
-msgstr "Tempo entre a alteração de 1% volume (millisec)"
+msgid "Time it takes to reach 0% volume (minutes)"
+msgstr "Tempo que leva para atingir o volume de 0% (minutos)"
msgctxt "#30007"
msgid "Next check time if dialog is cancelled (minutes)"
@@ -128,3 +128,7 @@ msgstr "Sempre"
msgctxt "#30028"
msgid "Specific Time"
msgstr "Tempo especifico"
+
+msgctxt "#30029"
+msgid "Set the minimum volume %"
+msgstr "Defina o volume mínimo %"
\ No newline at end of file
diff --git a/resources/settings.xml b/resources/settings.xml
index a9443d3..e1200e6 100644
--- a/resources/settings.xml
+++ b/resources/settings.xml
@@ -1,10 +1,11 @@
-
+
-
+
+
@@ -14,14 +15,16 @@
-
-
+
+
-
+
+
+
diff --git a/service.py b/service.py
index 6dee062..db58bad 100644
--- a/service.py
+++ b/service.py
@@ -18,6 +18,7 @@
import time
import datetime
+import math
import xbmc
import xbmcplugin
import xbmcgui
@@ -30,8 +31,8 @@
addon_id = 'service.sleeptimer'
selfAddon = xbmcaddon.Addon(addon_id)
-datapath = xbmc.translatePath(selfAddon.getAddonInfo('profile')).decode('utf-8')
-addonfolder = xbmc.translatePath(selfAddon.getAddonInfo('path')).decode('utf-8')
+datapath = xbmcvfs.translatePath(selfAddon.getAddonInfo('profile'))
+addonfolder = xbmcvfs.translatePath(selfAddon.getAddonInfo('path'))
debug=selfAddon.getSetting('debug_mode')
__version__ = selfAddon.getAddonInfo('version')
@@ -39,7 +40,8 @@
check_time_next = int(selfAddon.getSetting('check_time_next'))
time_to_wait = int(selfAddon.getSetting('waiting_time_dialog'))
audiochange = selfAddon.getSetting('audio_change')
-audiochangerate = int(selfAddon.getSetting('audio_change_rate'))
+muteVol = int(selfAddon.getSetting('mute_volume'))
+audiointervallength = int(selfAddon.getSetting('audio_interval_length'))
global audio_enable
audio_enable = str(selfAddon.getSetting('audio_enable'))
video_enable = str(selfAddon.getSetting('video_enable'))
@@ -48,19 +50,24 @@
enable_screensaver = selfAddon.getSetting('enable_screensaver')
custom_cmd = selfAddon.getSetting('custom_cmd')
cmd = selfAddon.getSetting('cmd')
+useAlternativeMode = selfAddon.getSetting('alternativemode')
# Functions:
def translate(text):
return selfAddon.getLocalizedString(text).encode('utf-8')
def _log( message ):
- print addon_id + ": " + str(message)
+ xbmc.log(addon_id + ": " + str(message), level=xbmc.LOGDEBUG)
+
+def _debug( message ):
+ if debug == 'true':
+ _log ( "DEBUG: " + str(message) )
# print the actual playing file in DEBUG-mode
def print_act_playing_file():
if debug == 'true':
actPlayingFile = xbmc.Player().getPlayingFile()
- _log ( "DEBUG: File: " + str(actPlayingFile) )
+ _log (str(actPlayingFile))
# wait for abort - xbmc.sleep or time.sleep doesn't work
# and prevents Kodi from exiting
@@ -104,12 +111,92 @@ def should_i_supervise(kodi_time,supervise_start_time,supervise_end_time):
else:
return False
+
+class AlternativeDetectionMode( xbmc.Player ):
+
+ def __init__( self, *args ):
+ _log ( "Init Alternative mode" )
+ self.resetTime()
+ self.lastEnded = None
+
+ def getSecondsFromNow(self, x):
+ return (datetime.datetime.now()-x).total_seconds()
+
+ def resetTime(self):
+ self.lastUserInteractionTime = datetime.datetime.now()
+
+ def onPlayBackSeekChapter(self, chapter):
+ _debug( "onPlayBackSeekChapter" )
+ self.resetTime()
+
+ def onPlayBackSeek(self, time, seekOffset):
+ _debug( "onPlayBackSeek" )
+ self.resetTime()
+
+ def onPlayBackResumed( self ):
+ # Will be called when xbmc starts playing a file
+ _debug( "onPlayBackResumed" )
+ self.resetTime()
+
+ def onPlayBackPaused( self ):
+ # Will be called when xbmc stops playing a file
+ _debug( "onPlayBackPaused" )
+ self.resetTime()
+
+ def onPlayBackStopped( self ):
+ # Will be called when user stops xbmc playing a file
+ _debug( "onPlayBackStopped" )
+ self.resetTime()
+
+ def onPlayBackStarted( self ):
+ # Will be called when user stops xbmc playing a file
+ if self.lastEnded is None:
+ _debug("onPlayBackStarted: No ended movie detected before => user interaction")
+ self.resetTime()
+ return
+
+ delayFromLastEnded = self.getSecondsFromNow(self.lastEnded)
+ _debug( "onPlayBackStarted: Last Ended was detected within " + str(delayFromLastEnded) + "seconds" )
+
+ if delayFromLastEnded is not None and delayFromLastEnded < 60:
+ _debug("onPlayBackStarted: Last movie endend => No user interaction")
+ #do nothing
+ else:
+ _debug("onPlayBackStarted: Last movie did not end during 60s => User interaction")
+ self.resetTime()
+
+
+ def onPlayBackEnded( self ):
+ _debug( "onPlayBackEnded" )
+ _debug("Storing last Ended time")
+ self.lastEnded = datetime.datetime.now()
+ #self.resetTime()
+
+ def getGlobalIdleTime(self):
+ result = int(self.getSecondsFromNow(self.lastUserInteractionTime))
+
+ _debug ( "XBMC Idle Time " + repr(xbmc.getGlobalIdleTime()))
+ _debug ( "Alternative Idle Time " + repr(result) )
+ return result
+
+
+
+def getIdleTimeInSeconds(alternativeMode):
+ if useAlternativeMode:
+ idle_time = alternativeMode.getGlobalIdleTime()
+ else:
+ idle_time = xbmc.getGlobalIdleTime()
+ return idle_time
+
class service:
def __init__(self):
FirstCycle = True
next_check = False
+ monitor = xbmc.Monitor()
+ alternativeMode = AlternativeDetectionMode()
+ diff_between_idle_and_check_time = None
- while True:
+ while not monitor.abortRequested():
kodi_time = get_kodi_time()
try:
supervise_start_time = int(selfAddon.getSetting('hour_start_sup').split(':')[0]+selfAddon.getSetting('hour_start_sup').split(':')[1])
@@ -140,26 +227,26 @@ def __init__(self):
_log ( "DEBUG: ################################################################" )
# Set this low values for easier debugging!
_log ( "DEBUG: debug is enabled! Override Settings:" )
- enable_audio = 'true'
+ #enable_audio = 'true'
_log ( "DEBUG: -> enable_audio: " + str(enable_audio) )
- maxaudio_time_in_minutes = 1
+ #maxaudio_time_in_minutes = 1
_log ( "DEBUG: -> maxaudio_time_in_minutes: " + str(maxaudio_time_in_minutes) )
- enable_video = 'true'
+ #enable_video = 'true'
_log ( "DEBUG: -> enable_video: " + str(enable_audio) )
- maxvideo_time_in_minutes = 1
+ #maxvideo_time_in_minutes = 1
_log ( "DEBUG: -> maxvideo_time_in_minutes: " + str(maxvideo_time_in_minutes) )
- iCheckTime = 1
+ #iCheckTime = 1
_log ( "DEBUG: -> check_time: " + str(iCheckTime) )
_log ( "DEBUG: ----------------------------------------------------------------" )
# wait 15s before start to let Kodi finish the intro-movie
- if xbmc.Monitor().waitForAbort(15):
+ if monitor.waitForAbort(15):
break
max_time_in_minutes = -1
FirstCycle = False
-
- idle_time = xbmc.getGlobalIdleTime()
+
+ idle_time = getIdleTimeInSeconds(alternativeMode)
idle_time_in_minutes = int(idle_time)/60
if xbmc.Player().isPlaying():
@@ -182,8 +269,7 @@ def __init__(self):
what_is_playing = "audio"
max_time_in_minutes = maxaudio_time_in_minutes
else:
- if debug == 'true':
- _log ( "DEBUG: Player is playing Audio, but check is disabled" )
+ _debug ( "DEBUG: Player is playing Audio, but check is disabled" )
do_next_check(iCheckTime)
continue
@@ -195,8 +281,7 @@ def __init__(self):
what_is_playing = "video"
max_time_in_minutes = maxvideo_time_in_minutes
else:
- if debug == 'true':
- _log ( "DEBUG: Player is playing Video, but check is disabled" )
+ _debug ( "DEBUG: Player is playing Video, but check is disabled" )
do_next_check(iCheckTime)
continue
@@ -211,20 +296,16 @@ def __init__(self):
do_next_check(iCheckTime)
continue
- if debug == 'true':
- _log ( "DEBUG: what_is_playing: " + str(what_is_playing) )
-
- if debug == 'true':
- _log ( "DEBUG: idle_time: '" + str(idle_time) + "s'; idle_time_in_minutes: '" + str(idle_time_in_minutes) + "'" )
- _log ( "DEBUG: max_time_in_minutes: " + str(max_time_in_minutes) )
+ _debug ( "DEBUG: what_is_playing: " + str(what_is_playing) )
+ _debug ( "DEBUG: idle_time: '" + str(idle_time) + "s'; idle_time_in_minutes: '" + str(idle_time_in_minutes) + "'" )
+ _debug ( "DEBUG: max_time_in_minutes: " + str(max_time_in_minutes) )
# only display the Progressdialog, if audio or video is enabled AND idle limit is reached
# Check if what_is_playing is not "other" and idle time exceeds limit
if ( what_is_playing != "other" and idle_time_in_minutes >= max_time_in_minutes ):
- if debug == 'true':
- _log ( "DEBUG: idle_time exceeds max allowed. Display Progressdialog" )
+ _debug ( "DEBUG: idle_time exceeds max allowed. Display Progressdialog" )
ret = msgdialogprogress.create(translate(30000),translate(30001))
secs=0
@@ -238,12 +319,12 @@ def __init__(self):
percent = increment*secs/100
secs_left = str((time_to_wait - secs))
remaining_display = str(secs_left) + " seconds left."
- msgdialogprogress.update(percent,translate(30001),remaining_display)
+ msgdialogprogress.update(int(percent),translate(30001))
xbmc.sleep(1000)
if (msgdialogprogress.iscanceled()):
cancelled = True
- if debug == 'true':
- _log ( "DEBUG: Progressdialog cancelled" )
+ alternativeMode.resetTime()
+ _debug ( "DEBUG: Progressdialog cancelled" )
break
if cancelled == True:
iCheckTime = check_time_next
@@ -260,43 +341,66 @@ def __init__(self):
if audiochange == 'true':
resp = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "Application.GetProperties", "params": { "properties": [ "volume"] }, "id": 1}')
dct = json.loads(resp)
- muteVol = 10
- if (dct.has_key("result")) and (dct["result"].has_key("volume")):
+ if ("result" in dct) and ("volume" in dct["result"]):
curVol = dct["result"]["volume"]
+
+ _debug ( "DEBUG: Original volume value is " + str(curVol) )
for i in range(curVol - 1, muteVol - 1, -1):
+ _debug ( "DEBUG: Reducing volume to " + str(i))
xbmc.executebuiltin('SetVolume(%d,showVolumeBar)' % (i))
- # move down slowly
- xbmc.sleep(audiochangerate)
+ # move down slowly ((total mins / steps) * ms in a min)
+ # (curVol-muteVol) runs the full timer where a user might control their volume via kodi instead of cutting it short when assuming a set volume of 100%
+ xbmc.sleep(round(audiointervallength / (curVol - muteVol) * 60000))
+
+ #check if user pressed something while audio volume is going down and abort sleep process
+ idle_time_in_minutes = int(getIdleTimeInSeconds(alternativeMode))/60
+ if idle_time_in_minutes < max_time_in_minutes:
+ _debug ( "DEBUG: User pressed a key while volume is going down. Aborting sleep process" )
+ #set volume back
+ _debug ( "DEBUG: Setting back original volume" + str(dct["result"]["volume"]))
+ xbmc.executebuiltin('SetVolume(%d,showVolumeBar)' % (dct["result"]["volume"]))
+ iCheckTime = check_time_next
+ _log ( "Progressdialog cancelled, next check in " + str(iCheckTime) + " min" )
+ # set next_check, so that it opens the dialog after "iCheckTime"
+ next_check = True
+ cancelled = True
+ break
+ if cancelled:
+ continue
# stop player anyway
- xbmc.sleep(5000) # wait 5s before stopping
- xbmc.executebuiltin('PlayerControl(Stop)')
+ _debug ( "DEBUG: Waiting before stop" + str(curVol) )
+ monitor.waitForAbort(5) # wait 5s before stopping
if audiochange == 'true':
- xbmc.sleep(2000) # wait 2s before changing the volume back
- if (dct.has_key("result")) and (dct["result"].has_key("volume")):
+ #monitor.waitForAbort(2) # wait 2s before changing the volume back
+ if ("result" in dct) and ("volume" in dct["result"]):
curVol = dct["result"]["volume"]
+ _debug ( "DEBUG: Reset volume to original value" + str(curVol) )
# we can move upwards fast, because there is nothing playing
xbmc.executebuiltin('SetVolume(%d,showVolumeBar)' % (curVol))
+ else:
+ _debug ( "DEBUG: DID NOT Reset volume 1 to original value" + str(curVol) )
+ else:
+ _debug ( "DEBUG: DID NOT Reset volume 2 to original value" + str(curVol) )
+
+ _debug ( "DEBUG: Stopping... " + str(curVol) )
+ xbmc.executebuiltin('PlayerControl(Stop)')
if enable_screensaver == 'true':
- if debug == 'true':
- _log ( "DEBUG: Activating screensaver" )
- xbmc.executebuiltin('ActivateScreensaver')
-
- #Run a custom cmd after playback is stopped
+ _debug ( "DEBUG: Activating screensaver" )
+ xbmc.executebuiltin('ActivateScreensaver')
+
+ # Run a custom cmd after playback is stopped
if custom_cmd == 'true':
- if debug == 'true':
- _log ( "DEBUG: Running custom script" )
+ _debug ( "DEBUG: Running custom script" )
os.system(cmd)
else:
- if debug == 'true':
- _log ( "DEBUG: Playing the stream, time does not exceed max limit" )
+ _debug ( "DEBUG: Playing the stream, time does not exceed max limit" )
else:
- if debug == 'true':
- _log ( "DEBUG: Not playing any media file" )
+ _debug ( "DEBUG: Not playing any media file" )
# reset max_time_in_minutes
max_time_in_minutes = -1
@@ -306,5 +410,9 @@ def __init__(self):
_log ( "DEBUG: diff_between_idle_and_check_time: " + str(diff_between_idle_and_check_time) )
do_next_check(iCheckTime)
+ monitor.waitForAbort(1)
+ else:
+ do_next_check(check_time)
+ monitor.waitForAbort(1)
service()