159 lines
6.9 KiB
Python
159 lines
6.9 KiB
Python
from __future__ import (
|
|
division, absolute_import, print_function, unicode_literals
|
|
)
|
|
|
|
import os
|
|
import threading
|
|
|
|
import xbmc
|
|
import xbmcaddon
|
|
import xbmcgui
|
|
|
|
from resources.lib.play_utils import get_media_segments
|
|
from resources.lib.utils import seconds_to_ticks, ticks_to_seconds, translate_path
|
|
from resources.lib.intro_skipper_utils import get_setting_skip_action, set_correct_skip_info
|
|
|
|
|
|
from .lazylogger import LazyLogger
|
|
from .dialogs import SkipDialog
|
|
|
|
from typing import Literal
|
|
|
|
log = LazyLogger(__name__)
|
|
|
|
|
|
class IntroSkipperService(threading.Thread):
|
|
|
|
stop_thread = False
|
|
monitor = None
|
|
|
|
def __init__(self, play_monitor):
|
|
super(IntroSkipperService, self).__init__()
|
|
self.monitor = play_monitor
|
|
|
|
def run(self):
|
|
|
|
from .play_utils import get_jellyfin_playing_item
|
|
settings = xbmcaddon.Addon()
|
|
plugin_path = settings.getAddonInfo('path')
|
|
plugin_path_real = translate_path(os.path.join(plugin_path))
|
|
|
|
skip_intro_dialog = None
|
|
skip_credit_dialog = None
|
|
skip_commercial_dialog = None
|
|
skip_preview_dialog = None
|
|
skip_recap_dialog = None
|
|
|
|
segments = None
|
|
playing_item_id = None
|
|
|
|
log.debug("SkipService: starting service")
|
|
|
|
while not xbmc.Monitor().abortRequested() and not self.stop_thread:
|
|
player = xbmc.Player()
|
|
if player.isPlaying():
|
|
item_id = get_jellyfin_playing_item()
|
|
if item_id is not None:
|
|
log.debug("SkipService: playing item is from jellyfin : {0}".format(item_id))
|
|
|
|
# If item id has changed or is new, retrieve segments
|
|
if playing_item_id is None or playing_item_id != item_id :
|
|
log.debug("SkipService: item is new, retrieving media segments : {0}".format(item_id))
|
|
segments = get_media_segments(item_id)
|
|
|
|
# Setting global playing item to current playing item
|
|
playing_item_id = item_id
|
|
|
|
# Handle skip only on jellyfin items
|
|
current_ticks = seconds_to_ticks(player.getTime())
|
|
|
|
# Handle Intros
|
|
skip_intro_dialog = self.handle_dialog(plugin_path_real, skip_intro_dialog, item_id, current_ticks, player, segments, "Intro")
|
|
# Handle Credits
|
|
skip_credit_dialog = self.handle_dialog(plugin_path_real, skip_credit_dialog, item_id, current_ticks, player, segments, "Outro")
|
|
# Handle commercial
|
|
skip_commercial_dialog = self.handle_dialog(plugin_path_real, skip_commercial_dialog, item_id, current_ticks, player, segments, "Commercial")
|
|
# Handle preview
|
|
skip_preview_dialog = self.handle_dialog(plugin_path_real, skip_preview_dialog, item_id, current_ticks, player, segments, "Preview")
|
|
# Handle recap
|
|
skip_recap_dialog = self.handle_dialog(plugin_path_real, skip_recap_dialog, item_id, current_ticks, player, segments, "Recap")
|
|
|
|
else:
|
|
playing_item_id = None
|
|
if skip_intro_dialog is not None:
|
|
log.debug("SkipService: Playback stopped, killing Intro dialog")
|
|
skip_intro_dialog.close()
|
|
skip_intro_dialog = None
|
|
|
|
if skip_credit_dialog is not None:
|
|
log.debug("SkipService: Playback stopped, killing Outro dialog")
|
|
skip_credit_dialog.close()
|
|
skip_credit_dialog = None
|
|
|
|
if skip_commercial_dialog is not None:
|
|
log.debug("SkipService: Playback stopped, killing Commercial dialog")
|
|
skip_commercial_dialog.close()
|
|
skip_commercial_dialog = None
|
|
|
|
if skip_preview_dialog is not None:
|
|
log.debug("SkipService: Playback stopped, killing Preview dialog")
|
|
skip_preview_dialog.close()
|
|
skip_preview_dialog = None
|
|
|
|
if skip_recap_dialog is not None:
|
|
log.debug("SkipService: Playback stopped, killing Recap dialog")
|
|
skip_recap_dialog.close()
|
|
skip_recap_dialog = None
|
|
|
|
if xbmc.Monitor().waitForAbort(1):
|
|
break
|
|
|
|
xbmc.sleep(200)
|
|
|
|
|
|
def handle_dialog(self, plugin_path_real: str, dialog: SkipDialog, item_id: str, current_ticks: float, player: xbmc.Player, segments, type: Literal["Commercial", "Preview", "Recap", "Outro", "Intro"]):
|
|
skip_action = get_setting_skip_action(type)
|
|
|
|
# In case do nothing is selected return
|
|
if skip_action == "2":
|
|
log.debug("SkipService: ignore {0} is selected".format(type))
|
|
return None
|
|
|
|
if dialog is None:
|
|
log.debug("SkipService: init dialog")
|
|
dialog = SkipDialog("SkipDialog.xml", plugin_path_real, "default", "720p")
|
|
|
|
set_correct_skip_info(item_id, dialog, segments, type)
|
|
|
|
is_segment = False
|
|
if dialog.start is not None and dialog.end is not None:
|
|
# Resets the dismiss var so that button can reappear in case of navigation in the timecodes
|
|
if (current_ticks < dialog.start or current_ticks > dialog.end) and dialog.has_been_dissmissed is True:
|
|
log.debug("SkipService: {0} skip was dismissed. It is reset beacause timecode is outside of segment")
|
|
dialog.has_been_dissmissed = False
|
|
|
|
# Checks if segment is playing
|
|
is_segment = current_ticks >= dialog.start and current_ticks <= dialog.end
|
|
|
|
if skip_action == "1" and is_segment:
|
|
log.debug("SkipService: {0} is set to automatic skip, skipping segment".format(type))
|
|
# If auto skip is enabled, skips to semgent ends automatically
|
|
player.seekTime(ticks_to_seconds(dialog.end))
|
|
xbmcgui.Dialog().notification("JellyCon", "{0} Skipped".format(type))
|
|
elif skip_action == "0":
|
|
# Otherwise show skip dialog
|
|
if is_segment and not dialog.has_been_dissmissed:
|
|
log.debug("SkipService: {0} is playing, showing dialog".format(type))
|
|
dialog.show()
|
|
else:
|
|
# Could not find doc on what happens when closing a closed dialog, but it seems fine
|
|
log.debug("SkipService: {0} is not playing, closing dialog".format(type))
|
|
dialog.close()
|
|
|
|
return dialog
|
|
|
|
|
|
def stop_service(self):
|
|
log.debug("IntroSkipperService Stop Called")
|
|
self.stop_thread = True
|