Skip to content

Commit

Permalink
Prep for v2.0.7
Browse files Browse the repository at this point in the history
Use new module
  • Loading branch information
bossanova808 committed Oct 15, 2024
1 parent 2e8ed3d commit 6490a36
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 99 deletions.
7 changes: 5 additions & 2 deletions addon.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="script.service.playbackresumer" name="Kodi Playback Resumer" version="2.0.6" provider-name="bossanova808, bradvido88">
<addon id="script.service.playbackresumer" name="Kodi Playback Resumer" version="2.0.7" provider-name="bossanova808, bradvido88">
<requires>
<import addon="xbmc.python" version="3.0.0"/>
<import addon="script.module.bossanova808" version="1.0.0"/>
</requires>
<extension point="xbmc.service" library="default.py" />
<extension point="xbmc.addon.metadata">
Expand All @@ -15,7 +16,9 @@
<source>https://github.com/bossanova808/script.service.playbackresumer</source>
<forum>https://forum.kodi.tv/showthread.php?tid=355383</forum>
<email>[email protected]</email>
<news>v2.0.6 - Add support for non-library videos</news>
<news>v2.0.7
- Remove old common code, use new module
</news>
<assets>
<icon>icon.png</icon>
</assets>
Expand Down
6 changes: 3 additions & 3 deletions default.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-

from bossanova808 import exception_logger
from resources.lib import playback_resumer

if __name__ == "__main__":
playback_resumer.run()
with exception_logger.log_exception():
playback_resumer.run()
10 changes: 5 additions & 5 deletions resources/lib/monitor.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import xbmc
from .common import *
from bossanova808.logger import Logger
# noinspection PyPackages
from .store import Store


class KodiEventMonitor(xbmc.Monitor):

def __init__(self, *args, **kwargs):
xbmc.Monitor.__init__(self)
log('KodiEventMonitor __init__')
Logger.debug('KodiEventMonitor __init__')

def onSettingsChanged(self):
log('onSettingsChanged - reload them.')
Logger.info('onSettingsChanged - reload them.')
Store.load_config_from_settings()

def onAbortRequested(self):
log('onAbortRequested')
log("Abort Requested")
Logger.debug('onAbortRequested')
11 changes: 6 additions & 5 deletions resources/lib/playback_resumer.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
from .common import *
from bossanova808.utilities import *
# noinspection PyPackages
from .store import Store
import xbmc
# noinspection PyPackages
from .monitor import KodiEventMonitor
# noinspection PyPackages
from .player import KodiPlayer


def run():
"""
This is 'main'
Expand All @@ -12,7 +16,7 @@ def run():
"""
footprints()
# load settings and create the store for our globals
config = Store()
Store()
Store.kodi_event_monitor = KodiEventMonitor(xbmc.Monitor)
Store.kodi_player = KodiPlayer(xbmc.Player)

Expand All @@ -26,6 +30,3 @@ def run():
break

footprints(False)



123 changes: 63 additions & 60 deletions resources/lib/player.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
from random import randint

from .common import *
from bossanova808.logger import Logger
from bossanova808.notify import Notify
from bossanova808.utilities import *

# noinspection PyPackages
from .store import Store
import json
import time
Expand All @@ -15,48 +19,48 @@ class KodiPlayer(xbmc.Player):

def __init__(self, *args):
xbmc.Player.__init__(self)
log('KodiPlayer __init__')
Logger.debug('KodiPlayer __init__')

def onPlayBackPaused(self):
log('onPlayBackPaused')
Logger.info('onPlayBackPaused')
Store.paused_time = time.time()
log(f'Playback paused at: {Store.paused_time}')
Logger.info(f'Playback paused at: {Store.paused_time}')

def onPlayBackEnded(self): # video ended normally (user didn't stop it)
log("onPlayBackEnded")
Logger.info("onPlayBackEnded")
self.update_resume_point(-1)
self.autoplay_random_if_enabled()

def onPlayBackStopped(self):
log("onPlayBackStopped")
Logger.info("onPlayBackStopped")
self.update_resume_point(-2)

def onPlayBackSeek(self, time, seekOffset):
log(f'onPlayBackSeek time {time}, seekOffset {seekOffset}')
Logger.info(f'onPlayBackSeek time {time}, seekOffset {seekOffset}')
try:
self.update_resume_point(self.getTime())
except RuntimeError:
log("Could not get playing time - seeked past end?")
Logger.warning("Could not get playing time - seeked past end? Clearing resume point.")
self.update_resume_point(0)
pass

def onPlayBackSeekChapter(self, chapter):
log(f'onPlayBackSeekChapter chapter: {chapter}')
Logger.info(f'onPlayBackSeekChapter chapter: {chapter}')
try:
self.update_resume_point(self.getTime())
except RuntimeError:
log("Could not get playing time - seeked past end?")
Logger.warning("Could not get playing time - seeked past end? Clearing resume point.")
self.update_resume_point(0)
pass

def onAVStarted(self):
log("onAVStarted")
Logger.info("onAVStarted")

# Clean up - get rid of any data about any files previously played
Store.clear_old_play_details()

if not self.isPlayingVideo():
log("Not playing a video - skipping: " + self.getPlayingFile())
Logger.info("Not playing a video - skipping: " + self.getPlayingFile())
return

xbmc.sleep(1500) # give it a bit to start playing and let the stopped method finish
Expand All @@ -69,7 +73,7 @@ def onAVStarted(self):
try:
self.update_resume_point(self.getTime())
except RuntimeError:
log('Could not get current playback time from player')
Logger.error('Could not get current playback time from player')

for i in range(0, Store.save_interval_seconds):
# Shutting down or not playing video anymore...stop handling playback
Expand All @@ -92,7 +96,7 @@ def update_resume_point(self, seconds):

# short circuit if we haven't got a record of the file that is currently playing
if not Store.currently_playing_file_path:
log("No valid currently_playing_file_path found - therefore not setting resume point")
Logger.info("No valid currently_playing_file_path found - therefore not setting resume point")
return

# -1 indicates that the video has stopped playing
Expand All @@ -103,7 +107,7 @@ def update_resume_point(self, seconds):
for i in range(0, 30):

if Store.kodi_event_monitor.abortRequested():
log("Kodi is shutting down, and will save resume point")
Logger.info("Kodi is shutting down, so Kodi will save resume point")
# Kodi is shutting down while playing a video.
return

Expand All @@ -115,19 +119,19 @@ def update_resume_point(self, seconds):

# Short circuit if current time < Kodi's ignoresecondsatstart setting
if 0 < seconds < Store.ignore_seconds_at_start:
log(f'Not updating resume point as current time ({seconds}) is below Kodi\'s ignoresecondsatstart'
f' setting of {Store.ignore_seconds_at_start}')
Logger.info(f'Not updating resume point as current time ({seconds}) is below Kodi\'s ignoresecondsatstart'
f' setting of {Store.ignore_seconds_at_start}')
return

# Short circuits

# Weird library ID
if Store.library_id and Store.library_id < 0:
log(f"No/invalid library id ({Store.library_id}) for {Store.currently_playing_file_path}")
Logger.info(f"No/invalid library id ({Store.library_id}) for {Store.currently_playing_file_path}")
return
# Kodi doing its normal stopping thing
if seconds == -2:
log("Not updating Kodi native resume point because the file was stopped normally, so Kodi should do it itself")
Logger.info("Not updating Kodi native resume point because the file was stopped normally, so Kodi should do it itself")
return
# At this point if seconds is < 0, it is -1 meaning end of file/clear resume point
if seconds < 0:
Expand All @@ -137,22 +141,22 @@ def update_resume_point(self, seconds):
# if current time > Kodi's ignorepercentatend setting
percent_played = int((seconds * 100) / Store.length_of_currently_playing_file)
if percent_played > (100 - Store.ignore_percent_at_end):
log(f'Not updating resume point as current percent played ({percent_played}) is above Kodi\'s ignorepercentatend'
f' setting of {Store.ignore_percent_at_end}')
Logger.info(f'Not updating resume point as current percent played ({percent_played}) is above Kodi\'s ignorepercentatend'
f' setting of {Store.ignore_percent_at_end}')
return

# OK, BELOW HERE, we're probably going to set a resume point

# First update the resume point in the tracker file for later retrieval if needed
log(f'Setting custom resume seconds to {seconds}')
Logger.info(f'Setting custom resume seconds to {seconds}')
with open(Store.file_to_store_resume_point, 'w') as f:
f.write(str(seconds))

# Log what we are doing
if seconds == 0:
log(f'Removing resume point for: {Store.currently_playing_file_path}, type: {Store.type_of_video}, library id: {Store.library_id}')
Logger.info(f'Removing resume point for: {Store.currently_playing_file_path}, type: {Store.type_of_video}, library id: {Store.library_id}')
else:
log(f'Setting resume point for: {Store.currently_playing_file_path}, type: {Store.type_of_video}, library id: {Store.library_id}, to: {seconds} seconds')
Logger.info(f'Setting resume point for: {Store.currently_playing_file_path}, type: {Store.type_of_video}, library id: {Store.library_id}, to: {seconds} seconds')

# Determine the JSON-RPC setFooDetails method to use and what the library id name is based of the type of video
id_name = None
Expand All @@ -169,7 +173,7 @@ def update_resume_point(self, seconds):
get_method = 'VideoLibrary.GetMusicVideoDetails'
id_name = 'musicvideoid'
else:
log(f'Did not recognise type of video [{Store.type_of_video}] - assume non-library video')
Logger.info(f'Did not recognise type of video [{Store.type_of_video}] - assume non-library video')
method = 'Files.SetFileDetails'
get_method = 'Files.GetFileDetails'

Expand All @@ -180,11 +184,11 @@ def update_resume_point(self, seconds):
}
if id_name:
params = {
id_name: Store.library_id,
"resume": {
"position": seconds,
"total": Store.length_of_currently_playing_file
}
id_name: Store.library_id,
"resume": {
"position": seconds,
"total": Store.length_of_currently_playing_file
}
}
else:
params = {
Expand Down Expand Up @@ -236,20 +240,20 @@ def resume_if_was_playing(self):
with open(Store.file_to_store_resume_point, 'r') as f:
try:
resume_point = float(f.read())
except Exception as e:
log("Error reading resume point from file, therefore not resuming.")
except Exception:
Logger.error("Error reading resume point from file, therefore not resuming.")
return

# neg 1 means the video wasn't playing when Kodi ended
if resume_point < 0:
log("Not resuming playback because nothing was playing when Kodi last closed")
Logger.info("Not resuming playback because nothing was playing when Kodi last closed")
return False

with open(Store.file_to_store_last_played, 'r') as f:
full_path = f.read()

str_timestamp = '%d:%02d' % (resume_point / 60, resume_point % 60)
log(f'Will resume playback at {str_timestamp} of {full_path}')
Logger.info(f'Will resume playback at {str_timestamp} of {full_path}')

self.play(full_path)

Expand All @@ -258,7 +262,7 @@ def resume_if_was_playing(self):
if not self.isPlayingVideo() and not Store.kodi_event_monitor.abortRequested():
xbmc.sleep(100)
else:
notify(f'Resuming playback at {str_timestamp}', xbmcgui.NOTIFICATION_INFO)
Notify.info(f'Resuming playback at {str_timestamp}')
self.seekTime(resume_point)
return True

Expand All @@ -275,7 +279,7 @@ def get_random_library_video(self):
if not Store.video_types_in_library['episodes'] \
and not Store.video_types_in_library['movies'] \
and not Store.video_types_in_library['musicvideos']:
log('No episodes, movies, or music videos exist in the Kodi library. Cannot autoplay a random video.')
Logger.warning('No episodes, movies, or music videos exist in the Kodi library. Cannot autoplay a random video.')
return

random_int = randint(0, 2)
Expand All @@ -294,36 +298,36 @@ def get_random_library_video(self):
if not Store.video_types_in_library[result_type]:
return self.get_random_library_video() # get a different one

log(f'Getting a random video from: {result_type}')
Logger.info(f'Getting a random video from: {result_type}')

query = {
"jsonrpc": "2.0",
"id": "randomLibraryVideo",
"method": "VideoLibrary." + method,
"params": {
"limits": {
"end": 1
},
"sort": {
"method": "random"
},
"properties": [
"file"
]
}
"jsonrpc": "2.0",
"id": "randomLibraryVideo",
"method": "VideoLibrary." + method,
"params": {
"limits": {
"end": 1
},
"sort": {
"method": "random"
},
"properties": [
"file"
]
}
}

log(f'Executing JSON-RPC: {json.dumps(query)}')
Logger.info(f'Executing JSON-RPC: {json.dumps(query)}')
json_response = json.loads(xbmc.executeJSONRPC(json.dumps(query)))
log(f'JSON-RPC VideoLibrary.{method} response: {json.dumps(json_response)}')
Logger.info(f'JSON-RPC VideoLibrary.{method} response: {json.dumps(json_response)}')

# found a video!
if json_response['result']['limits']['total'] > 0:
Store.video_types_in_library[result_type] = True
return json_response['result'][result_type][0]['file']
# no videos of this type
else:
log("There are no " + result_type + " in the library")
Logger.info("There are no " + result_type + " in the library")
Store.video_types_in_library[result_type] = False
return self.get_random_library_video()

Expand All @@ -335,18 +339,17 @@ def autoplay_random_if_enabled(self):

if Store.autoplay_random:

log("Autoplay random is enabled in addon settings, so will play a new random video now.")
Logger.info("Autoplay random is enabled in addon settings, so will play a new random video now.")

video_playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)

# make sure the current playlist has finished completely
if not self.isPlayingVideo() \
and (video_playlist.getposition() == -1 or video_playlist.getposition() == video_playlist.size()):
full_path = self.get_random_library_video()
log("Auto-playing next random video because nothing is playing and playlist is empty: " + full_path)
Logger.info("Auto-playing next random video because nothing is playing and playlist is empty: " + full_path)
self.play(full_path)
notify(f'Auto-playing random video: {full_path}', xbmcgui.NOTIFICATION_INFO)
Notify.info(f'Auto-playing random video: {full_path}')
else:
log(f'Not auto-playing random as playlist not empty or something is playing.')
log(f'Current playlist position: {video_playlist.getposition()}, playlist size: {video_playlist.size()}')

Logger.info(f'Not auto-playing random as playlist not empty or something is playing.')
Logger.info(f'Current playlist position: {video_playlist.getposition()}, playlist size: {video_playlist.size()}')
Loading

0 comments on commit 6490a36

Please sign in to comment.