Files
seanime-docker/seanime-2.9.10/internal/torrentstream/playback.go
2025-09-20 14:08:38 +01:00

113 lines
3.6 KiB
Go

package torrentstream
import (
"context"
"seanime/internal/mediaplayers/mediaplayer"
"seanime/internal/nativeplayer"
)
type (
playback struct {
mediaPlayerCtxCancelFunc context.CancelFunc
// Stores the video duration returned by the media player
// When this is greater than 0, the video is considered to be playing
currentVideoDuration int
}
)
func (r *Repository) listenToMediaPlayerEvents() {
r.mediaPlayerRepositorySubscriber = r.mediaPlayerRepository.Subscribe("torrentstream")
if r.playback.mediaPlayerCtxCancelFunc != nil {
r.playback.mediaPlayerCtxCancelFunc()
}
var ctx context.Context
ctx, r.playback.mediaPlayerCtxCancelFunc = context.WithCancel(context.Background())
go func(ctx context.Context) {
for {
select {
case <-ctx.Done():
r.logger.Debug().Msg("torrentstream: Media player context cancelled")
return
case event := <-r.mediaPlayerRepositorySubscriber.EventCh:
switch e := event.(type) {
case mediaplayer.StreamingTrackingStartedEvent:
// Reset the current video duration, as the video has stopped
// DEVNOTE: This is changed in client.go as well when the duration is updated over 0
r.playback.currentVideoDuration = 0
case mediaplayer.StreamingVideoCompletedEvent:
case mediaplayer.StreamingTrackingStoppedEvent:
if r.client.currentTorrent.IsPresent() {
go func() {
defer func() {
if r := recover(); r != nil {
}
}()
r.logger.Debug().Msg("torrentstream: Media player stopped event received")
// Stop the stream
_ = r.StopStream()
}()
}
case mediaplayer.StreamingPlaybackStatusEvent:
go func() {
if e.Status != nil && r.client.currentTorrent.IsPresent() {
r.client.mediaPlayerPlaybackStatusCh <- e.Status
}
}()
}
}
}
}(ctx)
}
func (r *Repository) listenToNativePlayerEvents() {
r.nativePlayerSubscriber = r.nativePlayer.Subscribe("torrentstream")
go func() {
for {
select {
case event, ok := <-r.nativePlayerSubscriber.Events():
if !ok { // shouldn't happen
r.logger.Debug().Msg("torrentstream: Native player subscriber channel closed")
return
}
switch event := event.(type) {
case *nativeplayer.VideoLoadedMetadataEvent:
go func() {
if r.client.currentFile.IsPresent() && r.playback.currentVideoDuration == 0 {
// If the stored video duration is 0 but the media player status shows a duration that is not 0
// we know that the video has been loaded and is playing
if r.playback.currentVideoDuration == 0 && event.Duration > 0 {
// The media player has started playing the video
r.logger.Debug().Msg("torrentstream: Media player started playing the video, sending event")
r.sendStateEvent(eventTorrentStartedPlaying)
// Update the stored video duration
r.playback.currentVideoDuration = int(event.Duration)
}
}
}()
case *nativeplayer.VideoTerminatedEvent:
r.logger.Debug().Msg("torrentstream: Native player terminated event received")
r.playback.currentVideoDuration = 0
// Only handle the event if we actually have a current torrent to avoid unnecessary cleanup
if r.client.currentTorrent.IsPresent() {
go func() {
defer func() {
if rec := recover(); rec != nil {
r.logger.Error().Msg("torrentstream: Recovered from panic in VideoTerminatedEvent handler")
}
}()
r.logger.Debug().Msg("torrentstream: Stopping stream due to native player termination")
// Stop the stream
_ = r.StopStream()
}()
}
}
}
}
}()
}