Open probonopd opened 1 year ago
If you don't want this kind of functionality in this addon, would you know how to do it in a fork?
I would absolutely accept this kind of feature as a contribution. I realize it doesn't fully align with the stated goal of this project, but it aligns with the core idea behind it.
I would absolutely accept this kind of feature as a contribution.
That's great to hear, especially since upstream is not interested in channel-wide skips.
This being said, would you know where/how to best start?
The first problem that needs to be solved is how to identify the channel from the video ID. The addon only deals with the video id, because that's all it needs to interact with the API. I would start by looking into the youtube addon itself to see whether it exposes an API to fetch this information. If it doesn't this addon would have to interact with the YouTube API directly, but we should avoid that if at all possible.
Once you have that, you can just add inject another "skip segment" here:
We can get the channel_id
in the same way we are already getting the video_id
:
INFO <general>: [script.service.sponsorblock] monitor: {'video_id': 'AowJGns66_4', 'channel_id': 'UC5I2hjZYiW9gZPVkvzM8_Cw', 'status': {'unlisted': False, 'private': False, 'crawlable': True, 'family_safe': False, 'live': False}}
So, in resources/lib/monitor.py
we could do:
def __handle_playback_init(self, data):
try:
video_id = data["video_id"]
except KeyError:
logger.warning("received playbackinit notification without video id")
return
try:
channel_id = data["channel_id"]
except KeyError:
logger.warning("received playbackinit notification without channel id")
return
unlisted = data.get("unlisted", False)
if unlisted and addon.get_config(CONF_IGNORE_UNLISTED, bool):
logger.info("ignoring video %s because it's unlisted", video_id)
self._player_listener.ignore_next_video(video_id)
return
# preload the segments
self._player_listener.preload_segments(video_id, channel_id)
But it looks like resources/lib/player_listener.py
actually uses get_video_id
from youtube_api.py
, so we might need to do a likewise get_channel_id
in youtube_api.py
? youtube_api.py
is using JSON RPC, e.g., to get the video_id
(in video_id_from_list_item
) by using a Player.GetItem
JSON RPC request.
Also, to be able to handle outros, we also need to check whether the video is live (if it is, we can't skip the outro), and get the duration from Player.GetProperties
JSON RPC (example curl below). Is this the way?
curl -d '{ "jsonrpc": "2.0", "method": "Player.GetProperties", "params": { "playerid": 1, "properties": ["totaltime", "live"] }, "id": 1 }' -H 'Content-type: application/json' -X P
OST http://localhost:8080/jsonrpc
{"id":1,"jsonrpc":"2.0","result":{"live":false,"totaltime":{"hours":0,"milliseconds":0,"minutes":21,"seconds":25}}}
you can just add inject another "skip segment" here
How so? Can you give an example how to skip 3 seconds starting at 0:00.000?
But it looks like
resources/lib/player_listener.py
actually usesget_video_id
fromyoutube_api.py
, so we might need to do a likewiseget_channel_id
inyoutube_api.py
?youtube_api.py
is using JSON RPC, e.g., to get thevideo_id
(invideo_id_from_list_item
) by using aPlayer.GetItem
JSON RPC request.
That's mainly so this addon works with videos being played outside of the youtube addon. The addon will even work just based on the video's thumbnail.
Historically, the RPC stuff was added to the youtube addon later on and now it's mainly used for pre-loading the segments before the video even starts.
In this case I think it's fine if the feature only works for videos played in the youtube addon, so if you can do it with the playback_init
method, go for it!
Also, to be able to handle outros, we also need to check whether the video is live (if it is, we can't skip the outro), and get the duration from
Player.GetProperties
JSON RPC (example curl below). Is this the way?
This looks correct, but I've been tricked by Kodi before, so make sure this actually switches to true
when you play a live stream.
How so? Can you give an example how to skip 3 seconds starting at 0:00.000?
Here you go:
def get_channel_related_segments(channel_id: str, total_video_duration: float) -> list[SponsorSegment]:
skip_intro_duration: float | None = 3.0 # TODO: read this from the config based on channel_id
skip_outro_duration: float | None = 17.0 # TODO: also read from config
segments: list[SponsorSegment] = []
if skip_intro_duration is not None and skip_intro_duration > 0.0:
segments.append(SponsorSegment(
# TODO: if we want to clean this up a bit we could add a new class 'SkipSegment' which only
# has 'start' and 'end' and then have two subclasses `SponsorSegment` and `ChannelConfigSegment`
# (or a better name :P).
# We need to handle these cases separately anyway because of the popup that's shown after a skip.
uuid=None,
category=None,
# TODO: maybe the start could be a config as well?
start=0.00,
end=skip_intro_duration,
))
if skip_outro_duration is not None and skip_outro_duration > 0.0:
segments.append(SponsorSegment(
uuid=None,
category=None,
start=total_video_duration - skip_outro_duration,
end=total_video_duration,
))
return segments
# and now in _prepare_segments
channel_id = None # TODO: get the channel id
self._segments = get_sponsor_segments(self._api, video_id)
if channel_id is not None:
self._segments.extend(get_channel_related_segments(channel_id, total_video_duration))
# make sure the segments are sorted in ascending order over time!
self._segments.sort(key=lambda seg: seg.start)
This is just an example to illustrate the idea, feel free to do it differently.
Would it be possible to skip a certain number of seconds at beginning and end of each video in a certain channel?
My use case is that a channel I am watching is using a fixed into and outro and I want to filter those out; as far as I know the SponsorBlock database does not allow for this (yet?).
If you don't want this kind of functionality in this addon, would you know how to do it in a fork?