Skip to content

Commit

Permalink
Skip initial silence (#1262)
Browse files Browse the repository at this point in the history
* added api endpoints for user setting

* fixed API endpoints

* watchPageData sets progress to end of first silence when user setting is set

* GetAutoSkipEnabled wraps result in json

* added front-end component

* added error handling when getting user setting

* make sure stream is not selfstream before skipping silence

* imported logger

* gofumpt everything

* updated db starter for better testing

* use correct logger

Co-authored-by: Joscha Henningsen <[email protected]>

* use correct logger

Co-authored-by: Joscha Henningsen <[email protected]>

---------

Co-authored-by: Joscha Henningsen <[email protected]>
  • Loading branch information
Mjaethers and joschahenningsen authored Jan 19, 2024
1 parent 49587e1 commit a0d815f
Show file tree
Hide file tree
Showing 19 changed files with 120 additions and 18 deletions.
6 changes: 4 additions & 2 deletions api/live_update.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ const (
UpdateTypeCourseWentLive = "course_went_live"
)

var liveUpdateListenerMutex sync.RWMutex
var liveUpdateListener = map[uint]*liveUpdateUserSessionsWrapper{}
var (
liveUpdateListenerMutex sync.RWMutex
liveUpdateListener = map[uint]*liveUpdateUserSessionsWrapper{}
)

type liveUpdateUserSessionsWrapper struct {
sessions []*realtime.Context
Expand Down
32 changes: 32 additions & 0 deletions api/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func configGinUsersRouter(router *gin.Engine, daoWrapper dao.DaoWrapper) {
router.POST("/api/users/settings/playbackSpeeds", routes.updatePlaybackSpeeds)
router.POST("/api/users/settings/seekingTime", routes.updateSeekingTime)
router.POST("/api/users/settings/customSpeeds", routes.updateCustomSpeeds)
router.POST("/api/users/settings/autoSkip", routes.updateAutoSkip)

router.POST("/api/users/resetPassword", routes.resetPassword)

Expand Down Expand Up @@ -723,6 +724,37 @@ func (r usersRoutes) updateSeekingTime(c *gin.Context) {
}
}

func (r usersRoutes) updateAutoSkip(c *gin.Context) {
u := c.MustGet("TUMLiveContext").(tools.TUMLiveContext).User
if u == nil {
_ = c.Error(tools.RequestError{
Status: http.StatusUnauthorized,
CustomMessage: "login required",
})
return
}
var req struct{ Value model.AutoSkipSetting }
if err := c.BindJSON(&req); err != nil {
_ = c.Error(tools.RequestError{
Status: http.StatusBadRequest,
CustomMessage: "can not bind body to request",
Err: err,
})
return
}

settingBytes, _ := json.Marshal(req.Value)
err := r.DaoWrapper.UsersDao.AddUserSetting(&model.UserSetting{UserID: u.ID, Type: model.AutoSkip, Value: string(settingBytes)})
if err != nil {
_ = c.Error(tools.RequestError{
Status: http.StatusInternalServerError,
CustomMessage: "can not add user setting",
Err: err,
})
return
}
}

func (r usersRoutes) exportPersonalData(c *gin.Context) {
var resp personalData
u := c.MustGet("TUMLiveContext").(tools.TUMLiveContext).User
Expand Down
2 changes: 1 addition & 1 deletion api/worker_grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -882,7 +882,7 @@ func getLivePreviewFromWorker(s *model.Stream, workerID string, client pb.ToWork
return err
}

if err := os.MkdirAll(pathprovider.TUMLiveTemporary, 0750); err != nil {
if err := os.MkdirAll(pathprovider.TUMLiveTemporary, 0o750); err != nil {
return err
}

Expand Down
4 changes: 2 additions & 2 deletions cmd/modelGen/modelGen.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func main() {
}

fmt.Println("Generating model...")
model_file, err := os.OpenFile(fmt.Sprintf("model/%s.go", d.NamePrivate), os.O_WRONLY|os.O_CREATE, 0644)
model_file, err := os.OpenFile(fmt.Sprintf("model/%s.go", d.NamePrivate), os.O_WRONLY|os.O_CREATE, 0o644)
if err != nil {
fmt.Println(err)
os.Exit(1)
Expand All @@ -46,7 +46,7 @@ func main() {

fmt.Println("Generating dao...")

dao_file, err := os.OpenFile(fmt.Sprintf("dao/%s.go", d.NamePrivate), os.O_WRONLY|os.O_CREATE, 0644)
dao_file, err := os.OpenFile(fmt.Sprintf("dao/%s.go", d.NamePrivate), os.O_WRONLY|os.O_CREATE, 0o644)
if err != nil {
fmt.Println(err)
os.Exit(1)
Expand Down
4 changes: 3 additions & 1 deletion docs/static/tum-live-starter.sql
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@ CREATE TABLE `lecture_halls` (

LOCK TABLES `lecture_halls` WRITE;
/*!40000 ALTER TABLE `lecture_halls` DISABLE KEYS */;
INSERT INTO `lecture_halls` VALUES (1,NULL,NULL,NULL,'HS001','Hörsaal 001',NULL,NULL,NULL,NULL,NULL,NULL,NULL);
/*!40000 ALTER TABLE `lecture_halls` ENABLE KEYS */;
UNLOCK TABLES;

Expand Down Expand Up @@ -606,6 +607,7 @@ CREATE TABLE `silences` (

LOCK TABLES `silences` WRITE;
/*!40000 ALTER TABLE `silences` DISABLE KEYS */;
INSERT INTO `silences` VALUES (1,'2024-01-14 21:16:37.000','2024-01-14 21:16:43.000',NULL,0,100,1),(2,'2024-01-14 21:17:00.000','2024-01-14 21:17:02.000',NULL,0,200,2);
/*!40000 ALTER TABLE `silences` ENABLE KEYS */;
UNLOCK TABLES;

Expand Down Expand Up @@ -813,7 +815,7 @@ CREATE TABLE `streams` (

LOCK TABLES `streams` WRITE;
/*!40000 ALTER TABLE `streams` DISABLE KEYS */;
INSERT INTO `streams` VALUES (1,'2022-04-18 13:45:58.657','2022-04-18 13:46:46.547',NULL,'VL 1: Was ist Bier?','',1,'2022-04-11 12:00:00.000','2022-04-11 13:00:00.000','','','',0,NULL,'c33dfc976efb410299e604b255db0127','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','',0,1,NULL,NULL,0,NULL,NULL,NULL,0,'',NULL),(2,'2022-04-18 13:46:25.841','2022-04-18 13:46:46.547',NULL,'VL 2: Wie mache ich Bier?','',1,'2022-04-18 12:00:00.000','2022-04-18 13:00:00.000','','','',0,NULL,'5815366e4010482687912588349bc5c0','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','',0,1,NULL,NULL,0,NULL,NULL,NULL,0,'',NULL),(4,'2022-04-18 13:46:46.547','2022-04-18 13:46:46.547',NULL,'VL 3: Rückblick','',1,'2026-02-19 12:00:00.000','2026-02-19 13:00:00.000','','','',0,NULL,'d8ce0b882dbc4d999b42c143ce07db5a','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','',0,0,NULL,NULL,0,NULL,NULL,NULL,0,'',NULL),(7,'2022-04-18 13:46:46.547','2022-04-18 13:46:46.547',NULL,'VL 1: Livestream','',2,'2022-02-19 12:00:00.000','2022-02-19 13:00:00.000','','','',0,NULL,'','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','',1,0,NULL,NULL,0,NULL,NULL,NULL,0,'',NULL),(8,'2022-04-18 13:46:46.547','2022-04-18 13:46:46.547',NULL,'VL 1: Intro to Go','',3,'2022-02-19 12:00:00.000','2022-02-19 12:00:00.000','','','',0,NULL,'d8ce0b882dbc4d999b42c143ce07db5a','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','',0,1,NULL,NULL,0,NULL,NULL,NULL,0,'',NULL);
INSERT INTO `streams` VALUES (1,'2022-04-18 13:45:58.657','2022-04-18 13:46:46.547',NULL,'VL 1: Was ist Bier?','',1,'2022-04-11 12:00:00.000','2022-04-11 12:09:56.000','','','',0,NULL,'c33dfc976efb410299e604b255db0127','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','',0,1,NULL,NULL,0,NULL,NULL,1,0,'',NULL),(2,'2022-04-18 13:46:25.841','2022-04-18 13:46:46.547',NULL,'VL 2: Wie mache ich Bier?','',1,'2022-04-18 12:00:00.000','2022-04-18 12:09:56.000','','','',0,NULL,'5815366e4010482687912588349bc5c0','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','',0,1,NULL,NULL,0,NULL,NULL,1,0,'',NULL),(4,'2022-04-18 13:46:46.547','2022-04-18 13:46:46.547',NULL,'VL 3: Rückblick','',1,'2026-02-19 12:00:00.000','2026-02-19 13:00:00.000','','','',0,NULL,'d8ce0b882dbc4d999b42c143ce07db5a','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','',0,0,NULL,NULL,0,NULL,NULL,1,0,'',NULL),(7,'2022-04-18 13:46:46.547','2022-04-18 13:46:46.547',NULL,'VL 1: Livestream','',2,'2022-02-19 12:00:00.000','2022-02-19 13:00:00.000','','','',0,NULL,'','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','',1,0,NULL,NULL,0,NULL,NULL,1,0,'',NULL),(8,'2022-04-18 13:46:46.547','2022-04-18 13:46:46.547',NULL,'VL 1: Intro to Go','',3,'2022-02-19 12:00:00.000','2022-02-19 12:00:00.000','','','',0,NULL,'d8ce0b882dbc4d999b42c143ce07db5a','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','https://stream.lrz.de/vod/_definst_/mp4:tum/RBG/bb.mp4/playlist.m3u8','',0,1,NULL,NULL,0,NULL,NULL,1,0,'',NULL);
/*!40000 ALTER TABLE `streams` ENABLE KEYS */;
UNLOCK TABLES;

Expand Down
15 changes: 15 additions & 0 deletions model/stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -410,3 +410,18 @@ func (s Stream) ToDTO() StreamDTO {
Duration: duration,
}
}

// FirstSilenceAsProgress returns the end of the first silence as a quotient of the length of the stream
func (s Stream) FirstSilenceAsProgress() float64 {
if len(s.Silences) == 0 {
return 0
}
// Sanity check: first silence at beginning of stream
if s.Silences[0].Start != 0 {
return 0
}
duration := s.End.Sub(s.Start).Seconds()
p := float64(s.Silences[0].End) / duration

return p
}
21 changes: 21 additions & 0 deletions model/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const (
CustomPlaybackSpeeds
SeekingTime
UserDefinedSpeeds
AutoSkip
)

type UserSetting struct {
Expand Down Expand Up @@ -197,6 +198,26 @@ func (u User) PreferredNameChangeAllowed() bool {
return true
}

// AutoSkipSetting wraps whether auto skip is enabled in JSON
type AutoSkipSetting struct {
Enabled bool `json:"enabled"`
}

// GetAutoSkipEnabled returns whether the user has enabled auto skip
func (u User) GetAutoSkipEnabled() (AutoSkipSetting, error) {
for _, setting := range u.Settings {
if setting.Type == AutoSkip {
var a AutoSkipSetting
err := json.Unmarshal([]byte(setting.Value), &a)
if err != nil {
return AutoSkipSetting{Enabled: false}, err
}
return a, nil
}
}
return AutoSkipSetting{Enabled: false}, nil
}

type argonParams struct {
memory uint32
iterations uint32
Expand Down
6 changes: 4 additions & 2 deletions tools/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ import (
"github.com/spf13/viper"
)

var Cfg Config
var Loc *time.Location
var (
Cfg Config
Loc *time.Location
)

func LoadConfig() {
initCache()
Expand Down
15 changes: 15 additions & 0 deletions web/template/user-settings.gohtml
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,21 @@
<label for="seek-time-20">20s</label>
</div>
</section>
<section x-data="{ autoSkip: {{toJson .TUMLiveContext.User.GetAutoSkipEnabled}} }">
<h2>Automatically Skip First Silence</h2>
<span class="mr-2">
<label class="relative inline-flex items-center cursor-pointer">
<input :checked="autoSkip.enabled" type="checkbox" x-model="autoSkip.enabled" class="sr-only peer"
@change="global.updatePreference(global.UserSetting.AutoSkip, autoSkip)"/>
<div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-600
dark:peer-focus:ring-indigo-600 rounded-full peer dark:bg-gray-600 peer-checked:after:translate-x-full
peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px]
after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5
after:transition-all dark:border-gray-600 peer-checked:bg-blue-600 dark:peer-checked:bg-indigo-600"></div>
<span class="ml-3 text-sm font-medium text-3">Skip</span>
</label>
</span>
</section>
<section>
<h2>Privacy & Data Protection</h2>
<a href="/api/users/exportData" download="personal_data.json"
Expand Down
1 change: 1 addition & 0 deletions web/ts/user-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export enum UserSetting {
PlaybackSpeeds = "playbackSpeeds",
SeekingTime = "seekingTime",
CustomSpeeds = "customSpeeds",
AutoSkip = "autoSkip",
}

export function updatePreference(t: UserSetting, value: string | boolean | number[]): Promise<string> {
Expand Down
12 changes: 12 additions & 0 deletions web/watch.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package web
import (
"errors"
"html/template"
"math"
"net/http"
"strconv"
"strings"
Expand Down Expand Up @@ -93,6 +94,17 @@ func (r mainRoutes) WatchPage(c *gin.Context) {
} else if len(progress) > 0 {
data.Progress = progress[0]
}

// Check if user wants to skip first silence
autoSkip, err := tumLiveContext.User.GetAutoSkipEnabled()
if err != nil {
logger.Error("Couldn't decode user setting", "err", err)
} else if autoSkip.Enabled {
// The length of the stream may mismatch with the length of the video if it is a self-stream
if tumLiveContext.Stream.LectureHallID != 0 {
data.Progress.Progress = math.Max(data.Progress.Progress, tumLiveContext.Stream.FirstSilenceAsProgress())
}
}
}
if c.Query("restart") == "1" {
c.Redirect(http.StatusFound, strings.Split(c.Request.RequestURI, "?")[0])
Expand Down
4 changes: 2 additions & 2 deletions worker/cfg/cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,11 @@ func SetConfig() {
if PersistDir == "" {
PersistDir = "."
}
err := os.MkdirAll(PersistDir, 0755)
err := os.MkdirAll(PersistDir, 0o755)
if err != nil {
log.Error(err)
}
err = os.MkdirAll(LogDir, 0755)
err = os.MkdirAll(LogDir, 0o755)
if err != nil {
log.Warn("Could not create log directory: ", err)
}
Expand Down
2 changes: 1 addition & 1 deletion worker/edge/edge.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ func fetchFile(host, file string) error {
return fmt.Errorf("parse file path: %s", file)
}
d := filepath.Dir(diskDir)
err = os.MkdirAll(d, 0755)
err = os.MkdirAll(d, 0o755)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion worker/worker/persist.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const persistFileName = "/persist.gob"

// writeOut writes out the persistable object to disk
func (p *Persistable) writeOut() error {
f, err := os.OpenFile(cfg.PersistDir+persistFileName, os.O_RDWR|os.O_CREATE, 0666)
f, err := os.OpenFile(cfg.PersistDir+persistFileName, os.O_RDWR|os.O_CREATE, 0o666)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion worker/worker/premiere.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func streamPremiere(ctx *StreamContext) {
"-acodec", "aac", "-b:a", "128k", "-ac", "2", "-ar", "48000", "-af", "aresample=async=1:min_hard_comp=0.100000:first_pts=0",
"-f", "flv", fmt.Sprintf("%s%s", ctx.ingestServer, ctx.streamName))
log.WithField("cmd", cmd.String()).Info("Starting premiere")
ffmpegErr, errFfmpegErrFile := os.OpenFile(fmt.Sprintf("%s/ffmpeg_%s.log", cfg.LogDir, ctx.getStreamName()), os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
ffmpegErr, errFfmpegErrFile := os.OpenFile(fmt.Sprintf("%s/ffmpeg_%s.log", cfg.LogDir, ctx.getStreamName()), os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0o644)
if errFfmpegErrFile == nil {
cmd.Stderr = ffmpegErr
} else {
Expand Down
2 changes: 1 addition & 1 deletion worker/worker/stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func stream(streamCtx *StreamContext) {
// persist stream command in context, so it can be killed later
streamCtx.streamCmd = cmd
log.WithField("cmd", cmd.String()).Info("Starting stream")
ffmpegErr, errFfmpegErrFile := os.OpenFile(fmt.Sprintf("%s/ffmpeg_%s.log", cfg.LogDir, streamCtx.getStreamName()), os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
ffmpegErr, errFfmpegErrFile := os.OpenFile(fmt.Sprintf("%s/ffmpeg_%s.log", cfg.LogDir, streamCtx.getStreamName()), os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0o644)
if errFfmpegErrFile == nil {
cmd.Stderr = ffmpegErr
} else {
Expand Down
2 changes: 1 addition & 1 deletion worker/worker/thumbnails.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func createVideoThumbnail(ctx *StreamContext, source string) error {
if err != nil {
return err
}
file, err := os.OpenFile(ctx.getLargeThumbnailSpriteFileName(), os.O_CREATE|os.O_WRONLY, 0644)
file, err := os.OpenFile(ctx.getLargeThumbnailSpriteFileName(), os.O_CREATE|os.O_WRONLY, 0o644)
if err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions worker/worker/transcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ func handleTranscodingOutput(stderr io.ReadCloser, inputTime float64, progressCh
// creates folder for output file if it doesn't exist
func prepare(out string) error {
dir := filepath.Dir(out)
err := os.MkdirAll(dir, 0750)
err := os.MkdirAll(dir, 0o750)
if err != nil {
return fmt.Errorf("create output directory for transcoding: %s", err)
}
Expand All @@ -159,7 +159,7 @@ func prepare(out string) error {
// markForDeletion moves the file to $recfolder/.trash/
func markForDeletion(ctx *StreamContext) error {
trashName := ctx.getRecordingTrashName()
err := os.MkdirAll(filepath.Dir(trashName), 0750)
err := os.MkdirAll(filepath.Dir(trashName), 0o750)
if err != nil {
return fmt.Errorf("create trash directory: %s", err)
}
Expand Down
2 changes: 1 addition & 1 deletion worker/worker/upload_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func createDummyFile(filesize uint) (string, error) {
if err != nil {
return "", err
}
f, err := os.OpenFile(file.Name(), os.O_APPEND|os.O_WRONLY, 0600)
f, err := os.OpenFile(file.Name(), os.O_APPEND|os.O_WRONLY, 0o600)
if err != nil {
return "", err
}
Expand Down

0 comments on commit a0d815f

Please sign in to comment.