Skip to content

Commit

Permalink
Workaround Kodi crashes during forced playlist playback
Browse files Browse the repository at this point in the history
  • Loading branch information
MoojMidge committed Dec 13, 2024
1 parent a358a26 commit 38a2d88
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -197,44 +197,50 @@ def add_items(self, items, loads=False):

return len(items)

def play_playlist_item(self, position, resume=False):
def play_playlist_item(self, position, resume=False, defer=False):
"""
Function to play item in playlist from a specified position, where the
first item in the playlist is position 1
"""

context = self._context
playlist_id = self._playlist.getPlayListId()

if position == 'next':
position, _ = self.get_position(offset=1)
context = self._context
if not position:
context.log_warning('Unable to play from playlist position: {0}'
.format(position))
return
context.log_debug('Playing from playlist position: {0}'
.format(position))
context.log_debug('Playing from playlist: {id}, position: {position}'
.format(id=playlist_id,
position=position))

if not resume:
self._player.play(self._playlist, startpos=position - 1)
return
command = 'Playlist.PlayOffset({type},{position})'.format(
type=self.PLAYLIST_MAP.get(playlist_id) or 'video',
position=position - 1,
)
if defer:
return ''.join(('command://', command))
return self._context.execute(command)

# JSON Player.Open can be too slow but is needed if resuming is enabled
jsonrpc(method='Player.Open',
params={'item': {'playlistid': self._playlist.getPlayListId(),
params={'item': {'playlistid': playlist_id,
# Convert 1 indexed to 0 indexed position
'position': position - 1}},
options={'resume': True},
no_response=True)

def play(self, playlist_index=-1):
def play(self, playlist_index=-1, defer=False):
"""
We call the player in this way, because 'Player.play(...)' will call the addon again while the instance is
running. This is somehow shitty, because we couldn't release any resources and in our case we couldn't release
the cache. So this is the solution to prevent a locked database (sqlite).
We call the player in this way, because 'Player.play(...)' will call the
addon again while the instance is running. This is somehow shitty,
because we couldn't release any resources and in our case we couldn't
release the cache. So this is the solution to prevent a locked database
(sqlite) and Kodi crashing.
"""
playlist_type = self.PLAYLIST_MAP.get(self._playlist.getPlayListId())
self._context.execute(
'Playlist.PlayOffset({type},{position})'
.format(type=playlist_type or 'video', position=playlist_index)
)

"""
playlist = None
Expand All @@ -249,6 +255,15 @@ def play(self, playlist_index=-1):
xbmc.Player().play(item=playlist)
"""

playlist_type = self.PLAYLIST_MAP.get(self._playlist.getPlayListId())
command = 'Playlist.PlayOffset({type},{position})'.format(
type=playlist_type or 'video',
position=playlist_index,
)
if defer:
return ''.join(('command://', command))
return self._context.execute(command)

def get_position(self, offset=0):
"""
Function to get current playlist position and number of remaining
Expand Down
28 changes: 12 additions & 16 deletions resources/lib/youtube_plugin/kodion/plugin/xbmc/xbmc_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,11 @@ def run(self, provider, context, focused=None):
if max_wait_time < 0:
context.log_error('Multiple busy dialogs active'
' - Unable to restart playback')
command = playlist_player.play_playlist_item(position,
defer=True)
result, post_run_action = self.uri_action(
context,
'command://Playlist.PlayOffset({type},{position})'
.format(type='video',
position=(position - 1)),
command,
)
succeeded = False
continue
Expand Down Expand Up @@ -229,24 +229,20 @@ def run(self, provider, context, focused=None):
result = options.get(force_resolve)

if result and result.__class__.__name__ in self._PLAY_ITEM_MAP:
uri = result.get_uri()

if result.playable:
if options.get(provider.RESULT_FORCE_PLAY) or not result.playable:
result, post_run_action = self.uri_action(
context,
result.get_uri()
)
else:
item = self._PLAY_ITEM_MAP[result.__class__.__name__](
context,
result,
show_fanart=show_fanart,
)
uri = result.get_uri()
if options.get(provider.RESULT_FORCE_PLAY):
playlist_player = context.get_playlist_player()
playlist_player.play_item(item=uri, listitem=item)
else:
xbmcplugin.setResolvedUrl(
handle, succeeded=True, listitem=item
)
else:
result, post_run_action = self.uri_action(context, uri)
xbmcplugin.setResolvedUrl(
handle, succeeded=True, listitem=item
)

if item_count:
context.apply_content()
Expand Down
35 changes: 23 additions & 12 deletions resources/lib/youtube_plugin/youtube/helper/yt_play.py
Original file line number Diff line number Diff line change
Expand Up @@ -426,37 +426,48 @@ def process_items_for_playlist(context,
elif play_from == 'end':
play_from = -1
if isinstance(play_from, int):
playlist_position = play_from
position = play_from
elif isinstance(play_from, string_type):
playlist_position = None
position = None
else:
playlist_position = False
position = False

# add videos to playlist
num_items = 0
for idx, item in enumerate(items):
if not item.playable:
continue
playlist_player.add(item)
if playlist_position is None and item.video_id == play_from:
playlist_position = num_items
num_items += 1
if position is None and item.video_id == play_from:
position = num_items

if not num_items:
return False

if isinstance(play_from, int):
if num_items >= play_from > 0:
playlist_position = play_from - 1
position = play_from
elif play_from < 0:
playlist_position = num_items + play_from
position = num_items + play_from
else:
playlist_position = 0
elif not playlist_position:
playlist_position = 0
position = 1
elif not position:
position = 1

if action == 'queue':
return items
if action == 'play':
playlist_player.play_playlist_item(playlist_position + 1)
return items[playlist_position]
ui = context.get_ui()
max_wait_time = position
while ui.busy_dialog_active() or playlist_player.size() < position:
max_wait_time -= 1
if max_wait_time < 0:
command = playlist_player.play_playlist_item(position,
defer=True)
return UriItem(command)
context.sleep(1)
else:
playlist_player.play_playlist_item(position)
return
return items[position - 1]

0 comments on commit 38a2d88

Please sign in to comment.