From 49587e1f48471c1addd4c562ed3eb47b1fa8beb1 Mon Sep 17 00:00:00 2001 From: Matthew Humphreys Date: Thu, 18 Jan 2024 18:53:46 +0100 Subject: [PATCH 1/3] Show watch progress in playlist view (#1307) * pass progress to StreamPlaylistEntry * correct padding * linted formatting --- api/stream.go | 46 ++++++++++++++------- web/assets/css/watch.css | 4 +- web/template/partial/stream/playlist.gohtml | 9 ++++ web/ts/data-store/stream-playlist.ts | 24 +++++++---- 4 files changed, 60 insertions(+), 23 deletions(-) diff --git a/api/stream.go b/api/stream.go index 9058a25cf..6f2ee9cb0 100644 --- a/api/stream.go +++ b/api/stream.go @@ -359,26 +359,44 @@ func (r streamRoutes) getStream(c *gin.Context) { func (r streamRoutes) getStreamPlaylist(c *gin.Context) { type StreamPlaylistEntry struct { - StreamID uint `json:"streamId"` - CourseSlug string `json:"courseSlug"` - StreamName string `json:"streamName"` - LiveNow bool `json:"liveNow"` - Watched bool `json:"watched"` - Start time.Time `json:"start"` - CreatedAt time.Time `json:"createdAt"` + StreamID uint `json:"streamId"` + CourseSlug string `json:"courseSlug"` + StreamName string `json:"streamName"` + LiveNow bool `json:"liveNow"` + Watched bool `json:"watched"` + Start time.Time `json:"start"` + StreamProgress model.StreamProgress `json:"streamProgress"` + CreatedAt time.Time `json:"createdAt"` } tumLiveContext := c.MustGet("TUMLiveContext").(tools.TUMLiveContext) + + // Create mapping of stream id to progress for all progresses of user + var streamIDs []uint + for _, stream := range tumLiveContext.Course.Streams { + streamIDs = append(streamIDs, stream.ID) + } + streamProgresses := make(map[uint]model.StreamProgress) + res, err := r.LoadProgress(tumLiveContext.User.ID, streamIDs) + if err != nil { + logger.Error("Couldn't load progresses", "err", err) + } else { + for _, progress := range res { + streamProgresses[progress.StreamID] = progress + } + } + var result []StreamPlaylistEntry for _, stream := range tumLiveContext.Course.Streams { result = append(result, StreamPlaylistEntry{ - StreamID: stream.ID, - CourseSlug: tumLiveContext.Course.Slug, - StreamName: stream.GetName(), - LiveNow: stream.LiveNow, - Watched: stream.Watched, - Start: stream.Start, - CreatedAt: stream.CreatedAt, + StreamID: stream.ID, + CourseSlug: tumLiveContext.Course.Slug, + StreamName: stream.GetName(), + LiveNow: stream.LiveNow, + Watched: stream.Watched, + Start: stream.Start, + StreamProgress: streamProgresses[stream.ID], + CreatedAt: stream.CreatedAt, }) } diff --git a/web/assets/css/watch.css b/web/assets/css/watch.css index 05b7ee1de..1e94242f0 100644 --- a/web/assets/css/watch.css +++ b/web/assets/css/watch.css @@ -1,5 +1,5 @@ .playlist-thumbnail { - @apply bg-gray-100 dark:bg-gray-800 rounded-lg mr-4 bg-cover transition-all duration-500 hover:shadow-xl dark:shadow-gray-900/75; + @apply relative bg-gray-100 dark:bg-gray-800 rounded-lg mr-4 bg-cover transition-all duration-500 hover:shadow-xl dark:shadow-gray-900/75; } /* Rendered, but not visible on the screen. Enables layout calculations. */ @@ -10,4 +10,4 @@ width: 100%; height: auto; overflow: visible; -} +} \ No newline at end of file diff --git a/web/template/partial/stream/playlist.gohtml b/web/template/partial/stream/playlist.gohtml index 065bd4d8e..001114dac 100644 --- a/web/template/partial/stream/playlist.gohtml +++ b/web/template/partial/stream/playlist.gohtml @@ -32,6 +32,15 @@
+
+
+ +
+

diff --git a/web/ts/data-store/stream-playlist.ts b/web/ts/data-store/stream-playlist.ts index 493744971..668715f33 100644 --- a/web/ts/data-store/stream-playlist.ts +++ b/web/ts/data-store/stream-playlist.ts @@ -1,15 +1,23 @@ import { Delete, getData, postData, putData, Time } from "../global"; import { StreamableMapProvider } from "./provider"; +import { Progress } from "../api/progress"; export class StreamPlaylistProvider extends StreamableMapProvider { protected async fetcher(streamId: number): Promise { const result = await StreamPlaylist.get(streamId); - return result - .map((e) => { - e.startDate = new Date(e.start); - return e; - }) - .sort((a, b) => (a.startDate < b.startDate ? -1 : 1)); + return ( + result + .map((e) => { + e.startDate = new Date(e.start); + return e; + }) + // Convert stream progress to Typescript object + .map((e) => { + e.progress = new Progress(JSON.parse(JSON.stringify(e.streamProgress))); + return e; + }) + .sort((a, b) => (a.startDate < b.startDate ? -1 : 1)) + ); } } @@ -20,10 +28,12 @@ export type StreamPlaylistEntry = { liveNow: boolean; watched: boolean; start: string; + streamProgress: string; createdAt: string; - // Client Generated + // Client generated to package data with Typescript constructors startDate: Date; + progress: Progress; }; const StreamPlaylist = { From a0d815f92cde11e573a8dd1b9cc44e689284e165 Mon Sep 17 00:00:00 2001 From: Matthew Humphreys Date: Fri, 19 Jan 2024 12:55:10 +0100 Subject: [PATCH 2/3] Skip initial silence (#1262) * 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 <44805696+joschahenningsen@users.noreply.github.com> * use correct logger Co-authored-by: Joscha Henningsen <44805696+joschahenningsen@users.noreply.github.com> --------- Co-authored-by: Joscha Henningsen <44805696+joschahenningsen@users.noreply.github.com> --- api/live_update.go | 6 ++++-- api/users.go | 32 +++++++++++++++++++++++++++++++ api/worker_grpc.go | 2 +- cmd/modelGen/modelGen.go | 4 ++-- docs/static/tum-live-starter.sql | 4 +++- model/stream.go | 15 +++++++++++++++ model/user.go | 21 ++++++++++++++++++++ tools/config.go | 6 ++++-- web/template/user-settings.gohtml | 15 +++++++++++++++ web/ts/user-settings.ts | 1 + web/watch.go | 12 ++++++++++++ worker/cfg/cfg.go | 4 ++-- worker/edge/edge.go | 2 +- worker/worker/persist.go | 2 +- worker/worker/premiere.go | 2 +- worker/worker/stream.go | 2 +- worker/worker/thumbnails.go | 2 +- worker/worker/transcode.go | 4 ++-- worker/worker/upload_test.go | 2 +- 19 files changed, 120 insertions(+), 18 deletions(-) diff --git a/api/live_update.go b/api/live_update.go index 7b7c756cf..ba93f0c4f 100644 --- a/api/live_update.go +++ b/api/live_update.go @@ -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 diff --git a/api/users.go b/api/users.go index 2afc0e454..175a70eff 100644 --- a/api/users.go +++ b/api/users.go @@ -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) @@ -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 diff --git a/api/worker_grpc.go b/api/worker_grpc.go index 13c909055..4db638931 100644 --- a/api/worker_grpc.go +++ b/api/worker_grpc.go @@ -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 } diff --git a/cmd/modelGen/modelGen.go b/cmd/modelGen/modelGen.go index a3dd1f9b2..c537a1594 100644 --- a/cmd/modelGen/modelGen.go +++ b/cmd/modelGen/modelGen.go @@ -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) @@ -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) diff --git a/docs/static/tum-live-starter.sql b/docs/static/tum-live-starter.sql index fcd1ae2ad..41044ecab 100644 --- a/docs/static/tum-live-starter.sql +++ b/docs/static/tum-live-starter.sql @@ -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; @@ -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; @@ -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; diff --git a/model/stream.go b/model/stream.go index ba717b9ca..fc3572c71 100755 --- a/model/stream.go +++ b/model/stream.go @@ -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 +} diff --git a/model/user.go b/model/user.go index 999adc4ab..5b30425b8 100755 --- a/model/user.go +++ b/model/user.go @@ -58,6 +58,7 @@ const ( CustomPlaybackSpeeds SeekingTime UserDefinedSpeeds + AutoSkip ) type UserSetting struct { @@ -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 diff --git a/tools/config.go b/tools/config.go index 8d2190007..f4c49aad3 100644 --- a/tools/config.go +++ b/tools/config.go @@ -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() diff --git a/web/template/user-settings.gohtml b/web/template/user-settings.gohtml index b24214b21..b3857a061 100644 --- a/web/template/user-settings.gohtml +++ b/web/template/user-settings.gohtml @@ -139,6 +139,21 @@ +
+

Automatically Skip First Silence

+ + + +

Privacy & Data Protection

{ diff --git a/web/watch.go b/web/watch.go index b966e7c12..f866d0f10 100644 --- a/web/watch.go +++ b/web/watch.go @@ -3,6 +3,7 @@ package web import ( "errors" "html/template" + "math" "net/http" "strconv" "strings" @@ -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]) diff --git a/worker/cfg/cfg.go b/worker/cfg/cfg.go index baf6f1b24..051f3d93d 100644 --- a/worker/cfg/cfg.go +++ b/worker/cfg/cfg.go @@ -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) } diff --git a/worker/edge/edge.go b/worker/edge/edge.go index 867ec1160..a29682d2d 100644 --- a/worker/edge/edge.go +++ b/worker/edge/edge.go @@ -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 } diff --git a/worker/worker/persist.go b/worker/worker/persist.go index 8da624d71..8eb45f733 100644 --- a/worker/worker/persist.go +++ b/worker/worker/persist.go @@ -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 } diff --git a/worker/worker/premiere.go b/worker/worker/premiere.go index 856230c31..56d3a7130 100644 --- a/worker/worker/premiere.go +++ b/worker/worker/premiere.go @@ -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 { diff --git a/worker/worker/stream.go b/worker/worker/stream.go index 8c73c2294..ebe062909 100644 --- a/worker/worker/stream.go +++ b/worker/worker/stream.go @@ -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 { diff --git a/worker/worker/thumbnails.go b/worker/worker/thumbnails.go index 9f212d97b..f621028c7 100644 --- a/worker/worker/thumbnails.go +++ b/worker/worker/thumbnails.go @@ -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 } diff --git a/worker/worker/transcode.go b/worker/worker/transcode.go index ed221dcb0..a58c0a94b 100644 --- a/worker/worker/transcode.go +++ b/worker/worker/transcode.go @@ -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) } @@ -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) } diff --git a/worker/worker/upload_test.go b/worker/worker/upload_test.go index 763eb5970..416cebb88 100644 --- a/worker/worker/upload_test.go +++ b/worker/worker/upload_test.go @@ -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 } From e9e41088f7aeaa0fd4271aa7ae2347daba3d9b41 Mon Sep 17 00:00:00 2001 From: Yiran Duan Date: Tue, 23 Jan 2024 20:36:11 +0100 Subject: [PATCH 3/3] 1306 usercontext menu inconsistent padding (#1309) * Align padding of header and items in tum-live-menu (fix #1306) * Minor changes to tum-live-menu ui * menu item: Reduce margin-right, so that the icons don't extend beyond the left boundary of the region * Revert "menu item: Reduce margin-right, so that the icons don't extend beyond the left boundary of the region" This reverts commit 94fe9f01a7d3973a3d391ce8327b8b7a785dcabf. * menu item: Reduce margin-right, so that the icons don't extend beyond the left boundary of the region * menu item: Make the icons vertically aligned in the center --- web/assets/css/home.css | 9 ++++++++- web/template/home.gohtml | 26 +++++++++++++------------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/web/assets/css/home.css b/web/assets/css/home.css index 057a8f7b4..4a490579d 100644 --- a/web/assets/css/home.css +++ b/web/assets/css/home.css @@ -218,13 +218,20 @@ } .tum-live-menu .tum-live-menu-item { - @apply flex items-center p-2 hover:bg-gray-100 dark:hover:bg-gray-800 my-2 w-full + @apply flex items-center py-2 px-4 hover:bg-gray-100 dark:hover:bg-gray-800 my-2 w-full } .tum-live-menu .tum-live-menu-item.active { @apply bg-gray-100 dark:bg-gray-800 } +.tum-live-menu .tum-live-menu-item .icon-wrapper { + width: 18px; + display: flex; + justify-content: center; + align-items: center; +} + .tum-live-course-list > header { @apply flex items-center justify-between mb-8 diff --git a/web/template/home.gohtml b/web/template/home.gohtml index 9a8d3ad5d..5498eac7f 100644 --- a/web/template/home.gohtml +++ b/web/template/home.gohtml @@ -84,8 +84,8 @@ {{if or (eq $user.Role 1) (eq $user.Role 2) }} -
- +
+

Admin

@@ -95,8 +95,8 @@
-