视频转码
-{{.Video.Title}}
-{{.Video.Description}}
-该视频需要转码才能播放
- - {{else if eq .Video.Status 1}} -转码中...
- {{else if eq .Video.Status 2}} -转码失败, 请联系管理员
- {{else if eq .Video.Status 200}} -恭喜您, 转码成功!
- {{end}} - -diff --git a/internal/handlers/home.go b/internal/handlers/home.go index b88d79d..0f929c6 100644 --- a/internal/handlers/home.go +++ b/internal/handlers/home.go @@ -8,16 +8,22 @@ import ( "github.com/zhang2092/mediahls/internal/db" ) -type pageData struct { +// obj + +// homePageData 首页数据 +type homePageData struct { Authorize Videos []db.Video } -func (server *Server) home(w http.ResponseWriter, r *http.Request) { - pd := pageData{} +// view + +// home 首页 +func (server *Server) homeView(w http.ResponseWriter, r *http.Request) { + data := homePageData{} auth, err := server.withCookie(r) if err == nil { - pd.Authorize = *auth + data.Authorize = *auth } ctx := r.Context() @@ -32,12 +38,9 @@ func (server *Server) home(w http.ResponseWriter, r *http.Request) { item.Description = temp log.Println(item.Description) } - pd.Videos = append(pd.Videos, item) + data.Videos = append(data.Videos, item) } } - renderHome(w, pd) -} -func renderHome(w http.ResponseWriter, data any) { renderLayout(w, data, "web/templates/home.html.tmpl") } diff --git a/internal/handlers/middleware.go b/internal/handlers/middleware.go index b92ff11..781a2f4 100644 --- a/internal/handlers/middleware.go +++ b/internal/handlers/middleware.go @@ -33,14 +33,13 @@ func (server *Server) authorizeMiddleware(next http.Handler) http.Handler { func (server *Server) withCookie(r *http.Request) (*Authorize, error) { cookie, err := r.Cookie(AuthorizeCookie) if err != nil { - log.Printf("get cookie: %v", err) return nil, err } u := &Authorize{} err = server.secureCookie.Decode(AuthorizeCookie, cookie.Value, u) if err != nil { - log.Printf("secure decode cookie: %v", err) + // log.Printf("secure decode cookie: %v", err) return nil, err } diff --git a/internal/handlers/render.go b/internal/handlers/render.go index 34da643..a6bd6ff 100644 --- a/internal/handlers/render.go +++ b/internal/handlers/render.go @@ -2,8 +2,9 @@ package handlers import ( "html/template" - "log" "net/http" + + "github.com/zhang2092/mediahls/internal/pkg/logger" ) // func render(w http.ResponseWriter, data any, tmpls ...string) { @@ -22,18 +23,19 @@ import ( // } // } +// renderLayout 渲染方法 带框架 func renderLayout(w http.ResponseWriter, data any, tmpls ...string) { tmpls = append(tmpls, "web/templates/base/header.html.tmpl", "web/templates/base/footer.html.tmpl") t, err := template.ParseFiles(tmpls...) if err != nil { - log.Printf("template parse: %v", err) + logger.Logger.Errorf("template parse: %v, %v", tmpls, err) w.WriteHeader(http.StatusInternalServerError) return } err = t.Execute(w, data) if err != nil { - log.Printf("template execute: %v", err) + logger.Logger.Errorf("template execute: %v, %v", tmpls, err) w.WriteHeader(http.StatusInternalServerError) return } diff --git a/internal/handlers/server.go b/internal/handlers/server.go index 069e2ad..7303b48 100644 --- a/internal/handlers/server.go +++ b/internal/handlers/server.go @@ -62,23 +62,25 @@ func (server *Server) setupRouter() { router.HandleFunc("/login", server.loginView).Methods(http.MethodGet) router.HandleFunc("/login", server.login).Methods(http.MethodPost) router.HandleFunc("/logout", server.logout).Methods(http.MethodGet) - router.HandleFunc("/", server.home).Methods(http.MethodGet) - router.HandleFunc("/play/{xid}", server.play).Methods(http.MethodGet) + + router.HandleFunc("/", server.homeView).Methods(http.MethodGet) + + router.HandleFunc("/play/{xid}", server.videoView).Methods(http.MethodGet) router.HandleFunc("/media/{xid}/stream/", server.stream).Methods(http.MethodGet) router.HandleFunc("/media/{xid}/stream/{segName:index[0-9]+.ts}", server.stream).Methods(http.MethodGet) subRouter := router.PathPrefix("/").Subrouter() subRouter.Use(server.authorizeMiddleware) + subRouter.HandleFunc("/me/videos", server.videosView).Methods(http.MethodGet) subRouter.HandleFunc("/me/videos/p{page}", server.videosView).Methods(http.MethodGet) - - subRouter.HandleFunc("/me/videos/create", server.createVideoView).Methods(http.MethodGet) - subRouter.HandleFunc("/me/videos/create/{xid}", server.createVideoView).Methods(http.MethodGet) - subRouter.HandleFunc("/me/videos/create", server.createVideo).Methods(http.MethodPost) + subRouter.HandleFunc("/me/videos/update", server.editVideoView).Methods(http.MethodGet) + subRouter.HandleFunc("/me/videos/update/{xid}", server.editVideoView).Methods(http.MethodGet) + subRouter.HandleFunc("/me/videos/update", server.editVideo).Methods(http.MethodPost) subRouter.HandleFunc("/upload_image", server.uploadImage).Methods(http.MethodPost) subRouter.HandleFunc("/upload_file", server.uploadVideo).Methods(http.MethodPost) - subRouter.HandleFunc("/transfer/{xid}", server.transferView).Methods(http.MethodGet) + subRouter.HandleFunc("/transfer/{xid}", server.transfer).Methods(http.MethodPost) server.router = router diff --git a/internal/handlers/upload.go b/internal/handlers/upload.go index ada9043..7b0f2ae 100644 --- a/internal/handlers/upload.go +++ b/internal/handlers/upload.go @@ -4,7 +4,6 @@ import ( "bufio" "errors" "io" - "log" "net/http" "os" "path" @@ -13,18 +12,20 @@ import ( nanoId "github.com/matoous/go-nanoid" "github.com/zhang2092/mediahls/internal/pkg/fileutil" + "github.com/zhang2092/mediahls/internal/pkg/logger" ) +// data + +// uploadVideo 上传视频 func (server *Server) uploadVideo(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() file, fileHeader, err := r.FormFile("file") if err != nil { + logger.Logger.Errorf("upload video receive: %v", err) w.WriteHeader(http.StatusBadRequest) - _, err = w.Write([]byte(err.Error())) - if err != nil { - log.Printf("%v", err) - } + w.Write([]byte(err.Error())) return } defer file.Close() @@ -81,12 +82,10 @@ func (server *Server) uploadVideo(w http.ResponseWriter, r *http.Request) { } w.WriteHeader(http.StatusOK) - _, err = w.Write([]byte("/" + filePath)) - if err != nil { - log.Printf("%v", err) - } + w.Write([]byte("/" + filePath)) } +// uploadImage 上传图片 func (server *Server) uploadImage(w http.ResponseWriter, r *http.Request) { defer func(Body io.ReadCloser) { _ = Body.Close() @@ -94,49 +93,33 @@ func (server *Server) uploadImage(w http.ResponseWriter, r *http.Request) { _, fh, err := r.FormFile("file") if err != nil { + logger.Logger.Errorf("upload image receive: %v", err) w.WriteHeader(http.StatusBadRequest) - _, err = w.Write([]byte(err.Error())) - if err != nil { - log.Printf("%v", err) - } + w.Write([]byte(err.Error())) return } f, err := fh.Open() if err != nil { - log.Printf("%v", err) + logger.Logger.Errorf("upload image read: %v", err) w.WriteHeader(http.StatusInternalServerError) - _, err = w.Write([]byte("读取图片失败")) - if err != nil { - log.Printf("%v", err) - } + w.Write([]byte("读取图片失败")) return } reader := bufio.NewReader(f) filePath, err := fileutil.UploadImage(reader) if errors.Is(err, fileutil.ErrUnsupportedFileFormat) { - log.Printf("%v", err) w.WriteHeader(http.StatusUnsupportedMediaType) - _, err = w.Write([]byte(fileutil.ErrUnsupportedFileFormat.Error())) - if err != nil { - log.Printf("%v", err) - } + w.Write([]byte(fileutil.ErrUnsupportedFileFormat.Error())) return } if err != nil { - log.Printf("%v", err) w.WriteHeader(http.StatusInternalServerError) - _, err = w.Write([]byte(err.Error())) - if err != nil { - log.Printf("%v", err) - } + w.Write([]byte(err.Error())) return } w.WriteHeader(http.StatusOK) - _, err = w.Write([]byte(filePath)) - if err != nil { - log.Printf("%v", err) - } + w.Write([]byte(filePath)) } diff --git a/internal/handlers/user.go b/internal/handlers/user.go index 9060066..9c61324 100644 --- a/internal/handlers/user.go +++ b/internal/handlers/user.go @@ -10,67 +10,49 @@ import ( pwd "github.com/zhang2092/mediahls/internal/pkg/password" ) +// obj + +// registerPageData 注册页面数据 +type registerPageData struct { + Authorize + Summary string + Email string + EmailMsg string + Username string + UsernameMsg string + Password string + PasswordMsg string +} + +// loginPageData 登录页面数据 +type loginPageData struct { + Authorize + Summary string + Email string + EmailMsg string + Password string + PasswordMsg string +} + +// view + +// registerView 注册页面 func (server *Server) registerView(w http.ResponseWriter, r *http.Request) { // 是否已经登录 server.isRedirect(w, r) renderRegister(w, nil) } -func renderRegister(w http.ResponseWriter, data any) { - renderLayout(w, data, "web/templates/user/register.html.tmpl") +// loginView 登录页面 +func (server *Server) loginView(w http.ResponseWriter, r *http.Request) { + // 是否已经登录 + server.isRedirect(w, r) + renderLogin(w, nil) } -// type userResponse struct { -// Username string `json:"username"` -// FullName string `json:"full_name"` -// Email string `json:"email"` -// PasswordChangedAt time.Time `json:"password_changed_at"` -// CreatedAt time.Time `json:"created_at"` -// } - -// func newUserResponse(user db.User) userResponse { -// return userResponse{ -// Username: user.Username, -// Email: user.Email, -// CreatedAt: user.CreatedAt, -// } -// } - -func viladatorRegister(email, username, password string) (*respErrs, bool) { - ok := true - errs := &respErrs{ - Email: email, - Username: username, - Password: password, - } - - if !ValidateRxEmail(email) { - errs.EmailErr = "请填写正确的邮箱地址" - ok = false - } - if !ValidateRxUsername(username) { - errs.UsernameErr = "名称(6-20,字母,数字)" - ok = false - } - if !ValidatePassword(password) { - errs.PasswordErr = "密码(8-20位)" - ok = false - } - - return errs, ok -} - -type respErrs struct { - Authorize - Summary string - Email string - Username string - Password string - EmailErr string - UsernameErr string - PasswordErr string -} +// data +// register 注册 func (server *Server) register(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() @@ -82,9 +64,9 @@ func (server *Server) register(w http.ResponseWriter, r *http.Request) { email := r.PostFormValue("email") username := r.PostFormValue("username") password := r.PostFormValue("password") - errs, ok := viladatorRegister(email, username, password) + resp, ok := viladatorRegister(email, username, password) if !ok { - renderRegister(w, errs) + renderRegister(w, resp) return } @@ -104,70 +86,33 @@ func (server *Server) register(w http.ResponseWriter, r *http.Request) { _, err = server.store.CreateUser(r.Context(), arg) if err != nil { if server.store.IsUniqueViolation(err) { - errs.Summary = "邮箱或名称已经存在" - renderRegister(w, errs) + resp.Summary = "邮箱或名称已经存在" + renderRegister(w, resp) return } - errs.Summary = "请求网络错误,请刷新重试" - renderRegister(w, errs) + resp.Summary = "请求网络错误,请刷新重试" + renderRegister(w, resp) return } http.Redirect(w, r, "/login", http.StatusFound) - - // rsp := newUserResponse(user) - // Respond(w, "ok", rsp, http.StatusOK) -} - -func (server *Server) loginView(w http.ResponseWriter, r *http.Request) { - // 是否已经登录 - server.isRedirect(w, r) - renderLogin(w, nil) -} - -func renderLogin(w http.ResponseWriter, data any) { - renderLayout(w, data, "web/templates/user/login.html.tmpl") -} - -// type loginUserResponse struct { -// AccessToken string `json:"access_token"` -// AccessTokenExpiresAt time.Time `json:"access_token_expires_at"` -// User userResponse `json:"user"` -// } - -func viladatorLogin(email, password string) (*respErrs, bool) { - ok := true - errs := &respErrs{ - Email: email, - Password: password, - } - - if !ValidateRxEmail(email) { - errs.EmailErr = "请填写正确的邮箱地址" - ok = false - } - if len(password) == 0 { - errs.PasswordErr = "请填写正确的密码" - ok = false - } - - return errs, ok } +// login 登录 func (server *Server) login(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() if err := r.ParseForm(); err != nil { - renderLogin(w, respErrs{Summary: "请求网络错误,请刷新重试"}) + renderLogin(w, registerPageData{Summary: "请求网络错误,请刷新重试"}) return } email := r.PostFormValue("email") password := r.PostFormValue("password") - errs, ok := viladatorLogin(email, password) + resp, ok := viladatorLogin(email, password) if !ok { - renderLogin(w, errs) + renderLogin(w, resp) return } @@ -175,27 +120,27 @@ func (server *Server) login(w http.ResponseWriter, r *http.Request) { user, err := server.store.GetUserByEmail(ctx, email) if err != nil { if server.store.IsNoRows(sql.ErrNoRows) { - errs.Summary = "邮箱或密码错误" - renderLogin(w, errs) + resp.Summary = "邮箱或密码错误" + renderLogin(w, resp) return } - errs.Summary = "请求网络错误,请刷新重试" - renderLogin(w, errs) + resp.Summary = "请求网络错误,请刷新重试" + renderLogin(w, resp) return } err = pwd.BcryptComparePassword(user.HashedPassword, password) if err != nil { - errs.Summary = "邮箱或密码错误" - renderLogin(w, errs) + resp.Summary = "邮箱或密码错误" + renderLogin(w, resp) return } encoded, err := server.secureCookie.Encode(AuthorizeCookie, &Authorize{ID: user.ID, Name: user.Username}) if err != nil { - errs.Summary = "请求网络错误,请刷新重试(cookie)" - renderLogin(w, errs) + resp.Summary = "请求网络错误,请刷新重试(cookie)" + renderLogin(w, resp) return } @@ -204,7 +149,65 @@ func (server *Server) login(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/", http.StatusFound) } +// logout 退出 func (server *Server) logout(w http.ResponseWriter, r *http.Request) { cookie.DeleteCookie(w, cookie.AuthorizeName) http.Redirect(w, r, "/login", http.StatusFound) } + +// method + +// renderRegister 渲染注册页面 +func renderRegister(w http.ResponseWriter, data any) { + renderLayout(w, data, "web/templates/user/register.html.tmpl") +} + +// renderLogin 渲染登录页面 +func renderLogin(w http.ResponseWriter, data any) { + renderLayout(w, data, "web/templates/user/login.html.tmpl") +} + +// viladatorRegister 校验注册数据 +func viladatorRegister(email, username, password string) (registerPageData, bool) { + ok := true + resp := registerPageData{ + Email: email, + Username: username, + Password: password, + } + + if !ValidateRxEmail(email) { + resp.EmailMsg = "请填写正确的邮箱地址" + ok = false + } + if !ValidateRxUsername(username) { + resp.UsernameMsg = "名称(6-20,字母,数字)" + ok = false + } + if !ValidatePassword(password) { + resp.PasswordMsg = "密码(8-20位)" + ok = false + } + + return resp, ok +} + +// viladatorLogin 校验登录数据 +func viladatorLogin(email, password string) (loginPageData, bool) { + ok := true + errs := loginPageData{ + Email: email, + Password: password, + } + + if !ValidateRxEmail(email) { + errs.EmailMsg = "请填写正确的邮箱地址" + ok = false + } + if len(password) == 0 { + errs.PasswordMsg = "请填写正确的密码" + ok = false + } + + return errs, ok +} diff --git a/internal/handlers/video.go b/internal/handlers/video.go index 387838f..0b4eb14 100644 --- a/internal/handlers/video.go +++ b/internal/handlers/video.go @@ -15,18 +15,48 @@ import ( "github.com/zhang2092/mediahls/internal/pkg/logger" ) -type playData struct { +// obj + +// videoPageData 播放页面数据 +type videoPageData struct { Authorize - Url string Video db.Video } -func (server *Server) play(w http.ResponseWriter, r *http.Request) { +// videosPageData 视频列表数据 +type videosPageData struct { + Authorize + Videos []db.Video +} + +// videoEditPageData 视频编辑数据 +type videoEditPageData struct { + Authorize + Summary string + ID string + IDMsg string + Title string + TitleMsg string + Images string + ImagesMsg string + Description string + DescriptionMsg string + OriginLink string + OriginLinkMsg string + Status int + StatusMsg string +} + +// view + +// videoView 视频播放页面 +func (server *Server) videoView(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) xid := vars["xid"] - video, _ := server.store.GetVideo(r.Context(), xid) - data := playData{ - Video: video, + data := videoPageData{} + video, err := server.store.GetVideo(r.Context(), xid) + if err == nil { + data.Video = video } auth, err := server.withCookie(r) if err == nil { @@ -35,59 +65,10 @@ func (server *Server) play(w http.ResponseWriter, r *http.Request) { renderLayout(w, data, "web/templates/video/play.html.tmpl") } -/* -// 直接播放mp4 -video, err := os.Open("web/statics/git.mp4") -if err != nil { - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte("failed to open file")) - return -} -defer video.Close() - -http.ServeContent(w, r, "git", time.Now(), video) -*/ - -func (server *Server) stream(response http.ResponseWriter, request *http.Request) { - vars := mux.Vars(request) - mId := vars["xid"] - segName, ok := vars["segName"] - if !ok { - mediaBase := getMediaBase(mId) - m3u8Name := "index.m3u8" - serveHlsM3u8(response, request, mediaBase, m3u8Name) - } else { - mediaBase := getMediaBase(mId) - serveHlsTs(response, request, mediaBase, segName) - } -} - -func getMediaBase(mId string) string { - mediaRoot := "media" - return fmt.Sprintf("%s/%s", mediaRoot, mId) -} - -func serveHlsM3u8(w http.ResponseWriter, r *http.Request, mediaBase, m3u8Name string) { - mediaFile := fmt.Sprintf("%s/%s", mediaBase, m3u8Name) - http.ServeFile(w, r, mediaFile) - w.Header().Set("Content-Type", "application/x-mpegURL") - -} - -func serveHlsTs(w http.ResponseWriter, r *http.Request, mediaBase, segName string) { - mediaFile := fmt.Sprintf("%s/%s", mediaBase, segName) - http.ServeFile(w, r, mediaFile) - w.Header().Set("Content-Type", "video/MP2T") -} - -type meVideoData struct { - Authorize - Videos []db.Video -} - +// videosView 视频列表页面 func (server *Server) videosView(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - data := meVideoData{ + data := videosPageData{ Authorize: withUser(ctx), } @@ -111,13 +92,14 @@ func (server *Server) videosView(w http.ResponseWriter, r *http.Request) { } } - renderLayout(w, data, "web/templates/me/videos.html.tmpl") + renderLayout(w, data, "web/templates/video/videos.html.tmpl") } -func (server *Server) createVideoView(w http.ResponseWriter, r *http.Request) { +// editVideoView 视频编辑页面 +func (server *Server) editVideoView(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) xid := vars["xid"] - vm := videoCreateResp{ + vm := videoEditPageData{ Authorize: withUser(r.Context()), } if len(xid) > 0 { @@ -130,79 +112,38 @@ func (server *Server) createVideoView(w http.ResponseWriter, r *http.Request) { vm.Status = int(v.Status) } } - renderCreateVideo(w, vm) + renderEditVideo(w, vm) } -func renderCreateVideo(w http.ResponseWriter, data any) { - renderLayout(w, data, "web/templates/video/edit.html.tmpl") +// data + +// stream 视频HLS播放处理 +func (server *Server) stream(response http.ResponseWriter, request *http.Request) { + vars := mux.Vars(request) + mId := vars["xid"] + segName, ok := vars["segName"] + if !ok { + mediaBase := getMediaBase(mId) + m3u8Name := "index.m3u8" + serveHlsM3u8(response, request, mediaBase, m3u8Name) + } else { + mediaBase := getMediaBase(mId) + serveHlsTs(response, request, mediaBase, segName) + } } -type videoCreateResp struct { - Authorize - Summary string - ID string - IDErr string - Title string - TitleErr string - Images string - ImagesErr string - Description string - DescriptionErr string - OriginLink string - OriginLinkErr string - Status int - StatusErr string -} - -func viladatorCreateVedio(r *http.Request) (*videoCreateResp, bool) { - ok := true - status, _ := strconv.Atoi(r.PostFormValue("status")) - errs := &videoCreateResp{ - Authorize: withUser(r.Context()), - ID: r.PostFormValue("id"), - Title: r.PostFormValue("title"), - Images: r.PostFormValue("images"), - Description: r.PostFormValue("description"), - OriginLink: r.PostFormValue("origin_link"), - Status: status, - } - - if len(errs.Title) == 0 { - errs.TitleErr = "请填写正确的标题" - ok = false - } - - exist, _ := fileutil.PathExists(strings.TrimPrefix(errs.Images, "/")) - if !exist { - errs.ImagesErr = "请先上传图片" - ok = false - } - - if len(errs.Description) == 0 { - errs.DescriptionErr = "请填写描述" - ok = false - } - - exist, _ = fileutil.PathExists(strings.TrimPrefix(errs.OriginLink, "/")) - if !exist { - errs.OriginLinkErr = "请先上传视频" - ok = false - } - - return errs, ok -} - -func (server *Server) createVideo(w http.ResponseWriter, r *http.Request) { +// editVideo 视频编辑 +func (server *Server) editVideo(w http.ResponseWriter, r *http.Request) { defer r.Body.Close() if err := r.ParseForm(); err != nil { - renderCreateVideo(w, videoCreateResp{Summary: "请求网络错误, 请刷新重试"}) + renderEditVideo(w, videoEditPageData{Summary: "请求网络错误, 请刷新重试"}) return } - vm, ok := viladatorCreateVedio(r) + vm, ok := viladatorEditVedio(r) if !ok { - renderCreateVideo(w, vm) + renderEditVideo(w, vm) return } @@ -222,22 +163,34 @@ func (server *Server) createVideo(w http.ResponseWriter, r *http.Request) { }) if err != nil { vm.Summary = "添加视频失败" - renderCreateVideo(w, vm) + renderEditVideo(w, vm) return } } else { - _, err := server.store.UpdateVideo(ctx, db.UpdateVideoParams{ + v, err := server.store.GetVideo(ctx, vm.ID) + if err != nil { + vm.Summary = "视频数据错误" + renderEditVideo(w, vm) + return + } + + var sta int32 = int32(vm.Status) + if sta != -1 && sta != 200 { + sta = v.Status + } + + _, err = server.store.UpdateVideo(ctx, db.UpdateVideoParams{ ID: vm.ID, Title: vm.Title, Description: vm.Description, Images: vm.Images, - Status: int32(vm.Status), + Status: sta, UpdateAt: curTime, UpdateBy: u.Name, }) if err != nil { vm.Summary = "更新视频失败" - renderCreateVideo(w, vm) + renderEditVideo(w, vm) return } } @@ -245,25 +198,7 @@ func (server *Server) createVideo(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/me/videos", http.StatusFound) } -type transferData struct { - Authorize - Video db.Video -} - -func (server *Server) transferView(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - xid := vars["xid"] - v, _ := server.store.GetVideo(r.Context(), xid) - data := transferData{ - Video: v, - } - u, err := server.withCookie(r) - if err == nil { - data.Authorize = *u - } - renderLayout(w, data, "web/templates/video/transfer.html.tmpl") -} - +// transfer 视频转码 func (server *Server) transfer(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) xid := vars["xid"] @@ -318,3 +253,82 @@ func (server *Server) transfer(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte("视频正在转码中, 请稍后刷新页面")) } + +// method + +// renderEditVideo 渲染视频编辑页面 +func renderEditVideo(w http.ResponseWriter, data any) { + renderLayout(w, data, "web/templates/video/edit.html.tmpl") +} + +// viladatorEditVedio 检验视频编辑数据 +func viladatorEditVedio(r *http.Request) (videoEditPageData, bool) { + ok := true + status, _ := strconv.Atoi(r.PostFormValue("status")) + resp := videoEditPageData{ + Authorize: withUser(r.Context()), + ID: r.PostFormValue("id"), + Title: r.PostFormValue("title"), + Images: r.PostFormValue("images"), + Description: r.PostFormValue("description"), + OriginLink: r.PostFormValue("origin_link"), + Status: status, + } + + if len(resp.Title) == 0 { + resp.TitleMsg = "请填写正确的标题" + ok = false + } + + exist, _ := fileutil.PathExists(strings.TrimPrefix(resp.Images, "/")) + if !exist { + resp.ImagesMsg = "请先上传图片" + ok = false + } + + if len(resp.Description) == 0 { + resp.DescriptionMsg = "请填写描述" + ok = false + } + + exist, _ = fileutil.PathExists(strings.TrimPrefix(resp.OriginLink, "/")) + if !exist { + resp.OriginLinkMsg = "请先上传视频" + ok = false + } + + return resp, ok +} + +// getMediaBase 获取视频m3u8文件路径 +func getMediaBase(mId string) string { + mediaRoot := "media" + return fmt.Sprintf("%s/%s", mediaRoot, mId) +} + +// serveHlsM3u8 返回m3u8文件 +func serveHlsM3u8(w http.ResponseWriter, r *http.Request, mediaBase, m3u8Name string) { + mediaFile := fmt.Sprintf("%s/%s", mediaBase, m3u8Name) + http.ServeFile(w, r, mediaFile) + w.Header().Set("Content-Type", "application/x-mpegURL") +} + +// serveHlsTs 返回ts文件 +func serveHlsTs(w http.ResponseWriter, r *http.Request, mediaBase, segName string) { + mediaFile := fmt.Sprintf("%s/%s", mediaBase, segName) + http.ServeFile(w, r, mediaFile) + w.Header().Set("Content-Type", "video/MP2T") +} + +/* +// 直接播放mp4 +video, err := os.Open("web/statics/git.mp4") +if err != nil { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte("failed to open file")) + return +} +defer video.Close() + +http.ServeContent(w, r, "git", time.Now(), video) +*/ diff --git a/internal/pkg/convert/hls.go b/internal/pkg/convert/hls.go index 6cdf786..292e3b4 100644 --- a/internal/pkg/convert/hls.go +++ b/internal/pkg/convert/hls.go @@ -1,12 +1,12 @@ package convert import ( - "log" "os" "os/exec" "strings" "github.com/zhang2092/mediahls/internal/pkg/fileutil" + "github.com/zhang2092/mediahls/internal/pkg/logger" ) func ConvertHLS(savePath, filePath string) error { @@ -20,18 +20,18 @@ func ConvertHLS(savePath, filePath string) error { binary, err := exec.LookPath("ffmpeg") if err != nil { - log.Println("1: ", err) + logger.Logger.Errorf("exec look path ffmpeg: %v", err) return err } // ffmpeg -i web/statics/git.mp4 -profile:v baseline -level 3.0 -s 1920x1080 -start_number 0 -hls_time 10 -hls_list_size 0 -hls_segment_filename %d.ts -f hls web/statics/git.m3u8 command := "-i " + filePath + " -profile:v baseline -level 3.0 -s 1920x1080 -start_number 0 -hls_time 10 -hls_list_size 0 -f hls " + savePath + "index.m3u8" - log.Println(command) + // log.Println(command) args := strings.Split(command, " ") cmd := exec.Command(binary, args...) _, err = cmd.Output() if err != nil { - log.Println("2: ", err) + logger.Logger.Errorf("ffmpeg cmd output: %v", err) return err } diff --git a/web/templates/me/upload.html.tmpl b/web/templates/me/upload.html.tmpl deleted file mode 100644 index 26f533f..0000000 --- a/web/templates/me/upload.html.tmpl +++ /dev/null @@ -1,9 +0,0 @@ -{{template "header" .}} -
{{.Video.Description}}
-该视频需要转码才能播放
- - {{else if eq .Video.Status 1}} -转码中...
- {{else if eq .Video.Status 2}} -转码失败, 请联系管理员
- {{else if eq .Video.Status 200}} -恭喜您, 转码成功!
- {{end}} - -