node build fixed
This commit is contained in:
284
seanime-2.9.10/internal/mediastream/repository.go
Normal file
284
seanime-2.9.10/internal/mediastream/repository.go
Normal file
@@ -0,0 +1,284 @@
|
||||
package mediastream
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/samber/mo"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"seanime/internal/database/models"
|
||||
"seanime/internal/events"
|
||||
"seanime/internal/mediastream/optimizer"
|
||||
"seanime/internal/mediastream/transcoder"
|
||||
"seanime/internal/mediastream/videofile"
|
||||
"seanime/internal/util/filecache"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type (
|
||||
Repository struct {
|
||||
transcoder mo.Option[*transcoder.Transcoder]
|
||||
optimizer *optimizer.Optimizer
|
||||
settings mo.Option[*models.MediastreamSettings]
|
||||
playbackManager *PlaybackManager
|
||||
mediaInfoExtractor *videofile.MediaInfoExtractor
|
||||
logger *zerolog.Logger
|
||||
wsEventManager events.WSEventManagerInterface
|
||||
fileCacher *filecache.Cacher
|
||||
reqMu sync.Mutex
|
||||
cacheDir string // where attachments are stored
|
||||
transcodeDir string // where stream segments are stored
|
||||
}
|
||||
|
||||
NewRepositoryOptions struct {
|
||||
Logger *zerolog.Logger
|
||||
WSEventManager events.WSEventManagerInterface
|
||||
FileCacher *filecache.Cacher
|
||||
}
|
||||
)
|
||||
|
||||
func NewRepository(opts *NewRepositoryOptions) *Repository {
|
||||
ret := &Repository{
|
||||
logger: opts.Logger,
|
||||
optimizer: optimizer.NewOptimizer(&optimizer.NewOptimizerOptions{
|
||||
Logger: opts.Logger,
|
||||
WSEventManager: opts.WSEventManager,
|
||||
}),
|
||||
settings: mo.None[*models.MediastreamSettings](),
|
||||
transcoder: mo.None[*transcoder.Transcoder](),
|
||||
wsEventManager: opts.WSEventManager,
|
||||
fileCacher: opts.FileCacher,
|
||||
mediaInfoExtractor: videofile.NewMediaInfoExtractor(opts.FileCacher, opts.Logger),
|
||||
}
|
||||
ret.playbackManager = NewPlaybackManager(ret)
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (r *Repository) IsInitialized() bool {
|
||||
return r.settings.IsPresent()
|
||||
}
|
||||
|
||||
func (r *Repository) OnCleanup() {
|
||||
|
||||
}
|
||||
|
||||
func (r *Repository) InitializeModules(settings *models.MediastreamSettings, cacheDir string, transcodeDir string) {
|
||||
if settings == nil {
|
||||
r.logger.Error().Msg("mediastream: Settings not present")
|
||||
return
|
||||
}
|
||||
// Create the temp directory
|
||||
err := os.MkdirAll(transcodeDir, 0755)
|
||||
if err != nil {
|
||||
r.logger.Error().Err(err).Msg("mediastream: Failed to create transcode directory")
|
||||
}
|
||||
|
||||
if settings.FfmpegPath == "" {
|
||||
settings.FfmpegPath = "ffmpeg"
|
||||
}
|
||||
|
||||
if settings.FfprobePath == "" {
|
||||
settings.FfprobePath = "ffprobe"
|
||||
}
|
||||
|
||||
// Set the settings
|
||||
r.settings = mo.Some[*models.MediastreamSettings](settings)
|
||||
|
||||
r.cacheDir = cacheDir
|
||||
r.transcodeDir = transcodeDir
|
||||
|
||||
// Set the optimizer settings
|
||||
r.optimizer.SetLibraryDir(settings.PreTranscodeLibraryDir)
|
||||
|
||||
// Initialize the transcoder
|
||||
if ok := r.initializeTranscoder(r.settings); ok {
|
||||
}
|
||||
|
||||
r.logger.Info().Msg("mediastream: Module initialized")
|
||||
}
|
||||
|
||||
// CacheWasCleared should be called when the cache directory is manually cleared.
|
||||
func (r *Repository) CacheWasCleared() {
|
||||
r.playbackManager.mediaContainers.Clear()
|
||||
}
|
||||
|
||||
func (r *Repository) ClearTranscodeDir() {
|
||||
r.reqMu.Lock()
|
||||
defer r.reqMu.Unlock()
|
||||
|
||||
r.logger.Trace().Msg("mediastream: Clearing transcode directory")
|
||||
|
||||
// Empty the transcode directory
|
||||
if r.transcodeDir != "" {
|
||||
files, err := os.ReadDir(r.transcodeDir)
|
||||
if err != nil {
|
||||
r.logger.Error().Err(err).Msg("mediastream: Failed to read transcode directory")
|
||||
return
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
err = os.RemoveAll(filepath.Join(r.transcodeDir, file.Name()))
|
||||
if err != nil {
|
||||
r.logger.Error().Err(err).Msg("mediastream: Failed to remove file from transcode directory")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
r.logger.Debug().Msg("mediastream: Transcode directory cleared")
|
||||
|
||||
r.playbackManager.mediaContainers.Clear()
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Optimize
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type StartMediaOptimizationOptions struct {
|
||||
Filepath string
|
||||
Quality optimizer.Quality
|
||||
AudioChannelIndex int
|
||||
}
|
||||
|
||||
func (r *Repository) StartMediaOptimization(opts *StartMediaOptimizationOptions) (err error) {
|
||||
if !r.IsInitialized() {
|
||||
return errors.New("module not initialized")
|
||||
}
|
||||
|
||||
mediaInfo, err := r.mediaInfoExtractor.GetInfo(r.settings.MustGet().FfmpegPath, opts.Filepath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = r.optimizer.StartMediaOptimization(&optimizer.StartMediaOptimizationOptions{
|
||||
Filepath: opts.Filepath,
|
||||
Quality: opts.Quality,
|
||||
MediaInfo: mediaInfo,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func (r *Repository) RequestOptimizedStream(filepath string) (ret *MediaContainer, err error) {
|
||||
if !r.IsInitialized() {
|
||||
return nil, errors.New("module not initialized")
|
||||
}
|
||||
|
||||
ret, err = r.playbackManager.RequestPlayback(filepath, StreamTypeOptimized)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Transcode
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
func (r *Repository) TranscoderIsInitialized() bool {
|
||||
return r.IsInitialized() && r.transcoder.IsPresent()
|
||||
}
|
||||
|
||||
func (r *Repository) RequestTranscodeStream(filepath string, clientId string) (ret *MediaContainer, err error) {
|
||||
r.reqMu.Lock()
|
||||
defer r.reqMu.Unlock()
|
||||
|
||||
r.logger.Debug().Str("filepath", filepath).Msg("mediastream: Transcode stream requested")
|
||||
|
||||
if !r.IsInitialized() {
|
||||
return nil, errors.New("module not initialized")
|
||||
}
|
||||
|
||||
// Reinitialize the transcoder for each new transcode request
|
||||
if ok := r.initializeTranscoder(r.settings); !ok {
|
||||
return nil, errors.New("real-time transcoder not initialized, check your settings")
|
||||
}
|
||||
|
||||
ret, err = r.playbackManager.RequestPlayback(filepath, StreamTypeTranscode)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *Repository) RequestPreloadTranscodeStream(filepath string) (err error) {
|
||||
r.logger.Debug().Str("filepath", filepath).Msg("mediastream: Transcode stream preloading requested")
|
||||
|
||||
if !r.IsInitialized() {
|
||||
return errors.New("module not initialized")
|
||||
}
|
||||
|
||||
_, err = r.playbackManager.PreloadPlayback(filepath, StreamTypeTranscode)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Direct Play
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
func (r *Repository) RequestDirectPlay(filepath string, clientId string) (ret *MediaContainer, err error) {
|
||||
r.reqMu.Lock()
|
||||
defer r.reqMu.Unlock()
|
||||
|
||||
r.logger.Debug().Str("filepath", filepath).Msg("mediastream: Direct play requested")
|
||||
|
||||
if !r.IsInitialized() {
|
||||
return nil, errors.New("module not initialized")
|
||||
}
|
||||
|
||||
ret, err = r.playbackManager.RequestPlayback(filepath, StreamTypeDirect)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (r *Repository) RequestPreloadDirectPlay(filepath string) (err error) {
|
||||
r.logger.Debug().Str("filepath", filepath).Msg("mediastream: Direct stream preloading requested")
|
||||
|
||||
if !r.IsInitialized() {
|
||||
return errors.New("module not initialized")
|
||||
}
|
||||
|
||||
_, err = r.playbackManager.PreloadPlayback(filepath, StreamTypeDirect)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
func (r *Repository) initializeTranscoder(settings mo.Option[*models.MediastreamSettings]) bool {
|
||||
// Destroy the old transcoder if it exists
|
||||
if r.transcoder.IsPresent() {
|
||||
tc, _ := r.transcoder.Get()
|
||||
tc.Destroy()
|
||||
}
|
||||
|
||||
r.transcoder = mo.None[*transcoder.Transcoder]()
|
||||
|
||||
// If the transcoder is not enabled, don't initialize the transcoder
|
||||
if !settings.MustGet().TranscodeEnabled {
|
||||
return false
|
||||
}
|
||||
|
||||
// If the temp directory is not set, don't initialize the transcoder
|
||||
if r.transcodeDir == "" {
|
||||
r.logger.Error().Msg("mediastream: Transcode directory not set, could not initialize transcoder")
|
||||
return false
|
||||
}
|
||||
|
||||
opts := &transcoder.NewTranscoderOptions{
|
||||
Logger: r.logger,
|
||||
HwAccelKind: settings.MustGet().TranscodeHwAccel,
|
||||
Preset: settings.MustGet().TranscodePreset,
|
||||
FfmpegPath: settings.MustGet().FfmpegPath,
|
||||
FfprobePath: settings.MustGet().FfprobePath,
|
||||
HwAccelCustomSettings: settings.MustGet().TranscodeHwAccelCustomSettings,
|
||||
TempOutDir: r.transcodeDir,
|
||||
}
|
||||
|
||||
tc, err := transcoder.NewTranscoder(opts)
|
||||
if err != nil {
|
||||
r.logger.Error().Err(err).Msg("mediastream: Failed to initialize transcoder")
|
||||
return false
|
||||
}
|
||||
|
||||
r.logger.Info().Msg("mediastream: Transcoder module initialized")
|
||||
r.transcoder = mo.Some[*transcoder.Transcoder](tc)
|
||||
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user