mirror of
https://github.com/teacat/chaturbate-dvr.git
synced 2025-10-29 16:59:59 +00:00
131 lines
3.4 KiB
Go
131 lines
3.4 KiB
Go
package channel
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"html/template"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
)
|
|
|
|
// Pattern holds the date/time and sequence information for the filename pattern
|
|
type Pattern struct {
|
|
Username string
|
|
Year string
|
|
Month string
|
|
Day string
|
|
Hour string
|
|
Minute string
|
|
Second string
|
|
Sequence int
|
|
}
|
|
|
|
// NextFile prepares the next file to be created, by cleaning up the last file and generating a new one
|
|
func (ch *Channel) NextFile() error {
|
|
if err := ch.Cleanup(); err != nil {
|
|
return err
|
|
}
|
|
filename, err := ch.GenerateFilename()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := ch.CreateNewFile(filename); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Increment the sequence number for the next file
|
|
ch.Sequence++
|
|
return nil
|
|
}
|
|
|
|
// Cleanup cleans the file and resets it, called when the stream errors out or before next file was created.
|
|
func (ch *Channel) Cleanup() error {
|
|
if ch.File == nil {
|
|
return nil
|
|
}
|
|
filename := ch.File.Name()
|
|
|
|
defer func() {
|
|
ch.Filesize = 0
|
|
ch.Duration = 0
|
|
}()
|
|
|
|
// Sync the file to ensure data is written to disk
|
|
if err := ch.File.Sync(); err != nil && !errors.Is(err, os.ErrClosed) {
|
|
return fmt.Errorf("sync file: %w", err)
|
|
}
|
|
if err := ch.File.Close(); err != nil && !errors.Is(err, os.ErrClosed) {
|
|
return fmt.Errorf("close file: %w", err)
|
|
}
|
|
|
|
// Delete the empty file
|
|
fileInfo, err := os.Stat(filename)
|
|
if err != nil && !os.IsNotExist(err) {
|
|
return fmt.Errorf("stat file delete zero file: %w", err)
|
|
}
|
|
if fileInfo != nil && fileInfo.Size() == 0 {
|
|
if err := os.Remove(filename); err != nil {
|
|
return fmt.Errorf("remove zero file: %w", err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GenerateFilename creates a filename based on the configured pattern and the current timestamp
|
|
func (ch *Channel) GenerateFilename() (string, error) {
|
|
var buf bytes.Buffer
|
|
|
|
// Parse the filename pattern defined in the channel's config
|
|
tpl, err := template.New("filename").Parse(ch.Config.Pattern)
|
|
if err != nil {
|
|
return "", fmt.Errorf("filename pattern error: %w", err)
|
|
}
|
|
|
|
// Get the current time based on the Unix timestamp when the stream was started
|
|
t := time.Unix(ch.StreamedAt, 0)
|
|
pattern := &Pattern{
|
|
Username: ch.Config.Username,
|
|
Sequence: ch.Sequence,
|
|
Year: t.Format("2006"),
|
|
Month: t.Format("01"),
|
|
Day: t.Format("02"),
|
|
Hour: t.Format("15"),
|
|
Minute: t.Format("04"),
|
|
Second: t.Format("05"),
|
|
}
|
|
|
|
if err := tpl.Execute(&buf, pattern); err != nil {
|
|
return "", fmt.Errorf("template execution error: %w", err)
|
|
}
|
|
return buf.String(), nil
|
|
}
|
|
|
|
// CreateNewFile creates a new file for the channel using the given filename
|
|
func (ch *Channel) CreateNewFile(filename string) error {
|
|
|
|
// Ensure the directory exists before creating the file
|
|
if err := os.MkdirAll(filepath.Dir(filename), 0777); err != nil {
|
|
return fmt.Errorf("mkdir all: %w", err)
|
|
}
|
|
|
|
// Open the file in append mode, create it if it doesn't exist
|
|
file, err := os.OpenFile(filename+".ts", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0777)
|
|
if err != nil {
|
|
return fmt.Errorf("cannot open file: %s: %w", filename, err)
|
|
}
|
|
|
|
ch.File = file
|
|
return nil
|
|
}
|
|
|
|
// ShouldSwitchFile determines whether a new file should be created.
|
|
func (ch *Channel) ShouldSwitchFile() bool {
|
|
maxFilesizeBytes := ch.Config.MaxFilesize * 1024 * 1024
|
|
maxDurationSeconds := ch.Config.MaxDuration * 60
|
|
|
|
return (ch.Duration >= float64(maxDurationSeconds) && ch.Config.MaxDuration > 0) ||
|
|
(ch.Filesize >= maxFilesizeBytes && ch.Config.MaxFilesize > 0)
|
|
}
|