Skip to content

Commit

Permalink
Add highly experimental skip outro support
Browse files Browse the repository at this point in the history
  • Loading branch information
Xameon42 authored Dec 5, 2023
1 parent 9c79611 commit 40ae4ac
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 1 deletion.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -401,11 +401,19 @@ Other miscellaneous configuration options. You probably won't have to change the

### Skip Intro Support

This functionality is considered experimental and requires the third-party [SkipIntro server plugin](https://github.com/ConfusedPolarBear/intro-skipper). It works the same ways as it did on MPV Shim for Plex.
This functionality is considered experimental and requires the third-party [SkipIntro server plugin fork*](https://github.com/jumoog/intro-skipper). It works the same ways as it did on MPV Shim for Plex.
(* Skip Credits needs forked repo with additonal release with credit support, see next Point)

- `skip_intro_always` - Always skip intros, without asking. Default: `false`
- `skip_intro_prompt` - Prompt to skip intro via seeking. Default: `false`

### Skip Credits / Outro Support

This functionality is considered experimental and requires the third-party [SkipIntro server plugin fork](https://github.com/jumoog/intro-skipper).

- `skip_credits_always` - Always skip intros, without asking. Default: `false`
- `skip_credits_prompt` - Prompt to skip intro via seeking. Default: `false`

### MPV Configuration

You can configure mpv directly using the `mpv.conf` and `input.conf` files. (It is in the same folder as `conf.json`.)
Expand Down
2 changes: 2 additions & 0 deletions jellyfin_mpv_shim/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ class Settings(SettingsBase):
health_check_interval: Optional[int] = 300
skip_intro_always: bool = False
skip_intro_prompt: bool = False
skip_credits_always: bool = False
skip_credits_prompt: bool = False
thumbnail_enable: bool = True
thumbnail_jellyscrub: bool = False
thumbnail_osc_builtin: bool = True
Expand Down
25 changes: 25 additions & 0 deletions jellyfin_mpv_shim/media.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ def __init__(
self.intro_tried = False
self.intro_start = None
self.intro_end = None
self.credits_tried = False
self.credits_start = None
self.credits_end = None

def map_streams(self):
self.subtitle_seq = {}
Expand Down Expand Up @@ -253,6 +256,25 @@ def get_intro(self, media_source_id):
exc_info=1,
)

def get_credits(self, media_source_id):
if self.credits_tried:
return
self.credits_tried = True

# provided by plugin
try:
skip_credits_data = self.client.jellyfin._get(
f"Episode/{media_source_id}/IntroSkipperSegments"
)
if skip_credits_data is not None and skip_credits_data["Credits"]["Valid"]:
self.credits_start = skip_credits_data["Credits"]["IntroStart"]
self.credits_end = skip_credits_data["Credits"]["IntroEnd"]
except:
log.warning(
"Fetching credits data failed. Do you have the plugin installed?",
exc_info=1,
)

def get_chapters(self):
return [
{"start": item["StartPositionTicks"] / 10000000, "name": item["Name"]}
Expand Down Expand Up @@ -337,6 +359,9 @@ def get_playback_url(
if settings.skip_intro_always or settings.skip_intro_prompt:
self.get_intro(self.media_source["Id"])

if settings.skip_credits_always or settings.skip_credits_prompt:
self.get_credits(self.media_source["Id"])

self.map_streams()
url = self._get_url_from_source()

Expand Down
2 changes: 2 additions & 0 deletions jellyfin_mpv_shim/menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,8 @@ def player_preferences_menu(self):
),
self.get_settings_toggle(_("Always Skip Intros"), "skip_intro_always"),
self.get_settings_toggle(_("Ask to Skip Intros"), "skip_intro_prompt"),
self.get_settings_toggle(_("Always Skip Credits"), "skip_credits_always"),
self.get_settings_toggle(_("Ask to Skip Credits"), "skip_credits_prompt"),
self.get_settings_toggle(
_("Enable thumbnail previews"), "thumbnail_enable"
),
Expand Down
44 changes: 44 additions & 0 deletions jellyfin_mpv_shim/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ def __init__(self):
self.update_check = UpdateChecker(self)
self.is_in_intro = False
self.intro_has_triggered = False
self.is_in_credits = False
self.credits_has_triggered = False
self.trickplay = None

if is_using_ext_mpv:
Expand Down Expand Up @@ -272,6 +274,8 @@ def handle_media_next():
if settings.media_key_seek:
if self.is_in_intro:
self.skip_intro()
elif self.is_in_credits:
self.skip_credits()
else:
_x, seektime = self.get_seek_times()
self.seek(seektime)
Expand Down Expand Up @@ -319,6 +323,8 @@ def menu_right():
else:
if self.is_in_intro:
self.skip_intro()
elif self.is_in_credits:
self.skip_credits()
else:
self.kb_seek("right")

Expand All @@ -329,6 +335,8 @@ def menu_up():
else:
if self.is_in_intro:
self.skip_intro()
elif self.is_in_credits:
self.skip_credits()
else:
self.kb_seek("up")

Expand Down Expand Up @@ -465,6 +473,11 @@ def skip_intro(self):
self.timeline_handle()
self.is_in_intro = False

def skip_credits(self):
self._player.playback_time = self._video.credits_end
self.timeline_handle()
self.is_in_credits = False

@synchronous("_lock")
def update(self):
if (
Expand All @@ -488,6 +501,27 @@ def update(self):
else:
self.is_in_intro = False

if (
(settings.skip_credits_always or settings.skip_credits_prompt)
and not self.syncplay.is_enabled()
and self._video is not None
and self._video.credits_start is not None
and self._player.playback_time is not None
and self._player.playback_time > self._video.credits_start
and self._player.playback_time < self._video.credits_end
):

if not self.is_in_credits:
if settings.skip_credits_always and not self.credits_has_triggered:
self.credits_has_triggered = True
self.skip_credits()
self._player.show_text(_("Skipped credits"), 3000, 1)
elif settings.skip_credits_prompt:
self._player.show_text(_("Seek to Skip credits"), 3000, 1)
self.is_in_credits = True
else:
self.is_in_credits = False

while not self.evt_queue.empty():
func, args = self.evt_queue.get()
func(*args)
Expand Down Expand Up @@ -549,6 +583,8 @@ def _play_media(
self._video = video
self.is_in_intro = False
self.intro_has_triggered = False
self.is_in_credits = False
self.credits_has_triggered = False
self.external_subtitles = {}
self.external_subtitles_rev = {}

Expand Down Expand Up @@ -677,6 +713,8 @@ def seek(
self.last_seek = offset
if self.is_in_intro and offset > self._player.playback_time:
self.skip_intro()
if self.is_in_credits and offset > self._player.playback_time:
self.skip_credits()
p2 = "absolute"
if exact:
p2 += "+exact"
Expand All @@ -690,6 +728,12 @@ def seek(
> self._player.playback_time
):
self.skip_intro()
if (
self.is_in_credits
and self._player.playback_time + offset
> self._player.playback_time
):
self.skip_credits()
if exact:
self._player.command("seek", offset, "exact")
else:
Expand Down

0 comments on commit 40ae4ac

Please sign in to comment.