onAVStarted was calling _fetch_sb_segments synchronously, which
subprocess.run()'s our sidecar — up to 8s of blocking on Kodi's
serialized player event thread. When the user started a new video while
one was playing, pv.youtube's stream resolve for the new video raced
with our blocked callback and the new play got dropped as "unplayable
item" before pv.youtube could finish.
Moved the segment fetch + skip loop into a background thread that
starts from onAVStarted and returns instantly. Player callbacks now
clear in microseconds.
Two big changes:
- service.py is a new background-service component (xbmc.service
extension). On first run it extracts the bundled pv.youtube 7.4.3 zip
into Kodi's addons dir, forces a rescan, enables it. No more two-step
install. The bundle stays as a separate Kodi addon at runtime; we just
ship + auto-install it.
- The service also subclasses xbmc.Player and runs SponsorBlock for
ANY YouTube playback, not just plays initiated by torttube. The
TorttubePlayerMonitor watches onAVStarted globally, pulls the YouTube
ID from the playing-file URL (matches ?v=, ?file=XXX.mpd, ?video_id=
— covers pv.youtube's resolved URLs in every shape), then runs a poll-
skip loop on a background thread. Critical: this means SponsorBlock
now works when a video is cast to Kodi from the phone YouTube app —
the cast hits pv.youtube directly and our plugin code is never
invoked, but the service is always alive and catches it.
- Dropped the three _attach_sponsorblock call sites in main.py._play()
and the SponsorBlockMonitor class. The DASH path still needs to block
until playback ends so it can shut down its localhost MPD server;
that's now a tiny _wait_for_playback_end() that doesn't do SB.
- Removed the <import addon="plugin.video.youtube"> from addon.xml since
we bundle it; kept inputstream.adaptive as an optional import.