代码优化
This commit is contained in:
parent
26c1f6aa72
commit
a2b0cd71b3
@ -8,16 +8,22 @@ import (
|
|||||||
"github.com/zhang2092/mediahls/internal/db"
|
"github.com/zhang2092/mediahls/internal/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
type pageData struct {
|
// obj
|
||||||
|
|
||||||
|
// homePageData 首页数据
|
||||||
|
type homePageData struct {
|
||||||
Authorize
|
Authorize
|
||||||
Videos []db.Video
|
Videos []db.Video
|
||||||
}
|
}
|
||||||
|
|
||||||
func (server *Server) home(w http.ResponseWriter, r *http.Request) {
|
// view
|
||||||
pd := pageData{}
|
|
||||||
|
// home 首页
|
||||||
|
func (server *Server) homeView(w http.ResponseWriter, r *http.Request) {
|
||||||
|
data := homePageData{}
|
||||||
auth, err := server.withCookie(r)
|
auth, err := server.withCookie(r)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
pd.Authorize = *auth
|
data.Authorize = *auth
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
@ -32,12 +38,9 @@ func (server *Server) home(w http.ResponseWriter, r *http.Request) {
|
|||||||
item.Description = temp
|
item.Description = temp
|
||||||
log.Println(item.Description)
|
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")
|
renderLayout(w, data, "web/templates/home.html.tmpl")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,14 +33,13 @@ func (server *Server) authorizeMiddleware(next http.Handler) http.Handler {
|
|||||||
func (server *Server) withCookie(r *http.Request) (*Authorize, error) {
|
func (server *Server) withCookie(r *http.Request) (*Authorize, error) {
|
||||||
cookie, err := r.Cookie(AuthorizeCookie)
|
cookie, err := r.Cookie(AuthorizeCookie)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("get cookie: %v", err)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
u := &Authorize{}
|
u := &Authorize{}
|
||||||
err = server.secureCookie.Decode(AuthorizeCookie, cookie.Value, u)
|
err = server.secureCookie.Decode(AuthorizeCookie, cookie.Value, u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("secure decode cookie: %v", err)
|
// log.Printf("secure decode cookie: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,8 +2,9 @@ package handlers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"html/template"
|
"html/template"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/zhang2092/mediahls/internal/pkg/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
// func render(w http.ResponseWriter, data any, tmpls ...string) {
|
// func render(w http.ResponseWriter, data any, tmpls ...string) {
|
||||||
@ -22,18 +23,19 @@ import (
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// renderLayout 渲染方法 带框架
|
||||||
func renderLayout(w http.ResponseWriter, data any, tmpls ...string) {
|
func renderLayout(w http.ResponseWriter, data any, tmpls ...string) {
|
||||||
tmpls = append(tmpls, "web/templates/base/header.html.tmpl", "web/templates/base/footer.html.tmpl")
|
tmpls = append(tmpls, "web/templates/base/header.html.tmpl", "web/templates/base/footer.html.tmpl")
|
||||||
t, err := template.ParseFiles(tmpls...)
|
t, err := template.ParseFiles(tmpls...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("template parse: %v", err)
|
logger.Logger.Errorf("template parse: %v, %v", tmpls, err)
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = t.Execute(w, data)
|
err = t.Execute(w, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("template execute: %v", err)
|
logger.Logger.Errorf("template execute: %v, %v", tmpls, err)
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,23 +62,25 @@ func (server *Server) setupRouter() {
|
|||||||
router.HandleFunc("/login", server.loginView).Methods(http.MethodGet)
|
router.HandleFunc("/login", server.loginView).Methods(http.MethodGet)
|
||||||
router.HandleFunc("/login", server.login).Methods(http.MethodPost)
|
router.HandleFunc("/login", server.login).Methods(http.MethodPost)
|
||||||
router.HandleFunc("/logout", server.logout).Methods(http.MethodGet)
|
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/", server.stream).Methods(http.MethodGet)
|
||||||
router.HandleFunc("/media/{xid}/stream/{segName:index[0-9]+.ts}", 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 := router.PathPrefix("/").Subrouter()
|
||||||
subRouter.Use(server.authorizeMiddleware)
|
subRouter.Use(server.authorizeMiddleware)
|
||||||
|
|
||||||
subRouter.HandleFunc("/me/videos", server.videosView).Methods(http.MethodGet)
|
subRouter.HandleFunc("/me/videos", server.videosView).Methods(http.MethodGet)
|
||||||
subRouter.HandleFunc("/me/videos/p{page}", server.videosView).Methods(http.MethodGet)
|
subRouter.HandleFunc("/me/videos/p{page}", server.videosView).Methods(http.MethodGet)
|
||||||
|
subRouter.HandleFunc("/me/videos/update", server.editVideoView).Methods(http.MethodGet)
|
||||||
subRouter.HandleFunc("/me/videos/create", server.createVideoView).Methods(http.MethodGet)
|
subRouter.HandleFunc("/me/videos/update/{xid}", server.editVideoView).Methods(http.MethodGet)
|
||||||
subRouter.HandleFunc("/me/videos/create/{xid}", server.createVideoView).Methods(http.MethodGet)
|
subRouter.HandleFunc("/me/videos/update", server.editVideo).Methods(http.MethodPost)
|
||||||
subRouter.HandleFunc("/me/videos/create", server.createVideo).Methods(http.MethodPost)
|
|
||||||
|
|
||||||
subRouter.HandleFunc("/upload_image", server.uploadImage).Methods(http.MethodPost)
|
subRouter.HandleFunc("/upload_image", server.uploadImage).Methods(http.MethodPost)
|
||||||
subRouter.HandleFunc("/upload_file", server.uploadVideo).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)
|
subRouter.HandleFunc("/transfer/{xid}", server.transfer).Methods(http.MethodPost)
|
||||||
|
|
||||||
server.router = router
|
server.router = router
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
@ -13,18 +12,20 @@ import (
|
|||||||
|
|
||||||
nanoId "github.com/matoous/go-nanoid"
|
nanoId "github.com/matoous/go-nanoid"
|
||||||
"github.com/zhang2092/mediahls/internal/pkg/fileutil"
|
"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) {
|
func (server *Server) uploadVideo(w http.ResponseWriter, r *http.Request) {
|
||||||
defer r.Body.Close()
|
defer r.Body.Close()
|
||||||
|
|
||||||
file, fileHeader, err := r.FormFile("file")
|
file, fileHeader, err := r.FormFile("file")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Logger.Errorf("upload video receive: %v", err)
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
_, err = w.Write([]byte(err.Error()))
|
w.Write([]byte(err.Error()))
|
||||||
if err != nil {
|
|
||||||
log.Printf("%v", err)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
@ -81,12 +82,10 @@ func (server *Server) uploadVideo(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_, err = w.Write([]byte("/" + filePath))
|
w.Write([]byte("/" + filePath))
|
||||||
if err != nil {
|
|
||||||
log.Printf("%v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// uploadImage 上传图片
|
||||||
func (server *Server) uploadImage(w http.ResponseWriter, r *http.Request) {
|
func (server *Server) uploadImage(w http.ResponseWriter, r *http.Request) {
|
||||||
defer func(Body io.ReadCloser) {
|
defer func(Body io.ReadCloser) {
|
||||||
_ = Body.Close()
|
_ = Body.Close()
|
||||||
@ -94,49 +93,33 @@ func (server *Server) uploadImage(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
_, fh, err := r.FormFile("file")
|
_, fh, err := r.FormFile("file")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Logger.Errorf("upload image receive: %v", err)
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
_, err = w.Write([]byte(err.Error()))
|
w.Write([]byte(err.Error()))
|
||||||
if err != nil {
|
|
||||||
log.Printf("%v", err)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := fh.Open()
|
f, err := fh.Open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("%v", err)
|
logger.Logger.Errorf("upload image read: %v", err)
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
_, err = w.Write([]byte("读取图片失败"))
|
w.Write([]byte("读取图片失败"))
|
||||||
if err != nil {
|
|
||||||
log.Printf("%v", err)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
reader := bufio.NewReader(f)
|
reader := bufio.NewReader(f)
|
||||||
filePath, err := fileutil.UploadImage(reader)
|
filePath, err := fileutil.UploadImage(reader)
|
||||||
if errors.Is(err, fileutil.ErrUnsupportedFileFormat) {
|
if errors.Is(err, fileutil.ErrUnsupportedFileFormat) {
|
||||||
log.Printf("%v", err)
|
|
||||||
w.WriteHeader(http.StatusUnsupportedMediaType)
|
w.WriteHeader(http.StatusUnsupportedMediaType)
|
||||||
_, err = w.Write([]byte(fileutil.ErrUnsupportedFileFormat.Error()))
|
w.Write([]byte(fileutil.ErrUnsupportedFileFormat.Error()))
|
||||||
if err != nil {
|
|
||||||
log.Printf("%v", err)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("%v", err)
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
_, err = w.Write([]byte(err.Error()))
|
w.Write([]byte(err.Error()))
|
||||||
if err != nil {
|
|
||||||
log.Printf("%v", err)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_, err = w.Write([]byte(filePath))
|
w.Write([]byte(filePath))
|
||||||
if err != nil {
|
|
||||||
log.Printf("%v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,67 +10,49 @@ import (
|
|||||||
pwd "github.com/zhang2092/mediahls/internal/pkg/password"
|
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) {
|
func (server *Server) registerView(w http.ResponseWriter, r *http.Request) {
|
||||||
// 是否已经登录
|
// 是否已经登录
|
||||||
server.isRedirect(w, r)
|
server.isRedirect(w, r)
|
||||||
renderRegister(w, nil)
|
renderRegister(w, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderRegister(w http.ResponseWriter, data any) {
|
// loginView 登录页面
|
||||||
renderLayout(w, data, "web/templates/user/register.html.tmpl")
|
func (server *Server) loginView(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// 是否已经登录
|
||||||
|
server.isRedirect(w, r)
|
||||||
|
renderLogin(w, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// type userResponse struct {
|
// data
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// register 注册
|
||||||
func (server *Server) register(w http.ResponseWriter, r *http.Request) {
|
func (server *Server) register(w http.ResponseWriter, r *http.Request) {
|
||||||
defer r.Body.Close()
|
defer r.Body.Close()
|
||||||
|
|
||||||
@ -82,9 +64,9 @@ func (server *Server) register(w http.ResponseWriter, r *http.Request) {
|
|||||||
email := r.PostFormValue("email")
|
email := r.PostFormValue("email")
|
||||||
username := r.PostFormValue("username")
|
username := r.PostFormValue("username")
|
||||||
password := r.PostFormValue("password")
|
password := r.PostFormValue("password")
|
||||||
errs, ok := viladatorRegister(email, username, password)
|
resp, ok := viladatorRegister(email, username, password)
|
||||||
if !ok {
|
if !ok {
|
||||||
renderRegister(w, errs)
|
renderRegister(w, resp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,70 +86,33 @@ func (server *Server) register(w http.ResponseWriter, r *http.Request) {
|
|||||||
_, err = server.store.CreateUser(r.Context(), arg)
|
_, err = server.store.CreateUser(r.Context(), arg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if server.store.IsUniqueViolation(err) {
|
if server.store.IsUniqueViolation(err) {
|
||||||
errs.Summary = "邮箱或名称已经存在"
|
resp.Summary = "邮箱或名称已经存在"
|
||||||
renderRegister(w, errs)
|
renderRegister(w, resp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
errs.Summary = "请求网络错误,请刷新重试"
|
resp.Summary = "请求网络错误,请刷新重试"
|
||||||
renderRegister(w, errs)
|
renderRegister(w, resp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
http.Redirect(w, r, "/login", http.StatusFound)
|
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) {
|
func (server *Server) login(w http.ResponseWriter, r *http.Request) {
|
||||||
defer r.Body.Close()
|
defer r.Body.Close()
|
||||||
|
|
||||||
if err := r.ParseForm(); err != nil {
|
if err := r.ParseForm(); err != nil {
|
||||||
renderLogin(w, respErrs{Summary: "请求网络错误,请刷新重试"})
|
renderLogin(w, registerPageData{Summary: "请求网络错误,请刷新重试"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
email := r.PostFormValue("email")
|
email := r.PostFormValue("email")
|
||||||
password := r.PostFormValue("password")
|
password := r.PostFormValue("password")
|
||||||
errs, ok := viladatorLogin(email, password)
|
resp, ok := viladatorLogin(email, password)
|
||||||
if !ok {
|
if !ok {
|
||||||
renderLogin(w, errs)
|
renderLogin(w, resp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,27 +120,27 @@ func (server *Server) login(w http.ResponseWriter, r *http.Request) {
|
|||||||
user, err := server.store.GetUserByEmail(ctx, email)
|
user, err := server.store.GetUserByEmail(ctx, email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if server.store.IsNoRows(sql.ErrNoRows) {
|
if server.store.IsNoRows(sql.ErrNoRows) {
|
||||||
errs.Summary = "邮箱或密码错误"
|
resp.Summary = "邮箱或密码错误"
|
||||||
renderLogin(w, errs)
|
renderLogin(w, resp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
errs.Summary = "请求网络错误,请刷新重试"
|
resp.Summary = "请求网络错误,请刷新重试"
|
||||||
renderLogin(w, errs)
|
renderLogin(w, resp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = pwd.BcryptComparePassword(user.HashedPassword, password)
|
err = pwd.BcryptComparePassword(user.HashedPassword, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs.Summary = "邮箱或密码错误"
|
resp.Summary = "邮箱或密码错误"
|
||||||
renderLogin(w, errs)
|
renderLogin(w, resp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
encoded, err := server.secureCookie.Encode(AuthorizeCookie, &Authorize{ID: user.ID, Name: user.Username})
|
encoded, err := server.secureCookie.Encode(AuthorizeCookie, &Authorize{ID: user.ID, Name: user.Username})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs.Summary = "请求网络错误,请刷新重试(cookie)"
|
resp.Summary = "请求网络错误,请刷新重试(cookie)"
|
||||||
renderLogin(w, errs)
|
renderLogin(w, resp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +149,65 @@ func (server *Server) login(w http.ResponseWriter, r *http.Request) {
|
|||||||
http.Redirect(w, r, "/", http.StatusFound)
|
http.Redirect(w, r, "/", http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// logout 退出
|
||||||
func (server *Server) logout(w http.ResponseWriter, r *http.Request) {
|
func (server *Server) logout(w http.ResponseWriter, r *http.Request) {
|
||||||
cookie.DeleteCookie(w, cookie.AuthorizeName)
|
cookie.DeleteCookie(w, cookie.AuthorizeName)
|
||||||
http.Redirect(w, r, "/login", http.StatusFound)
|
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
|
||||||
|
}
|
||||||
|
|||||||
@ -15,18 +15,48 @@ import (
|
|||||||
"github.com/zhang2092/mediahls/internal/pkg/logger"
|
"github.com/zhang2092/mediahls/internal/pkg/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
type playData struct {
|
// obj
|
||||||
|
|
||||||
|
// videoPageData 播放页面数据
|
||||||
|
type videoPageData struct {
|
||||||
Authorize
|
Authorize
|
||||||
Url string
|
|
||||||
Video db.Video
|
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)
|
vars := mux.Vars(r)
|
||||||
xid := vars["xid"]
|
xid := vars["xid"]
|
||||||
video, _ := server.store.GetVideo(r.Context(), xid)
|
data := videoPageData{}
|
||||||
data := playData{
|
video, err := server.store.GetVideo(r.Context(), xid)
|
||||||
Video: video,
|
if err == nil {
|
||||||
|
data.Video = video
|
||||||
}
|
}
|
||||||
auth, err := server.withCookie(r)
|
auth, err := server.withCookie(r)
|
||||||
if err == nil {
|
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")
|
renderLayout(w, data, "web/templates/video/play.html.tmpl")
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// videosView 视频列表页面
|
||||||
// 直接播放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
|
|
||||||
}
|
|
||||||
|
|
||||||
func (server *Server) videosView(w http.ResponseWriter, r *http.Request) {
|
func (server *Server) videosView(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
data := meVideoData{
|
data := videosPageData{
|
||||||
Authorize: withUser(ctx),
|
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)
|
vars := mux.Vars(r)
|
||||||
xid := vars["xid"]
|
xid := vars["xid"]
|
||||||
vm := videoCreateResp{
|
vm := videoEditPageData{
|
||||||
Authorize: withUser(r.Context()),
|
Authorize: withUser(r.Context()),
|
||||||
}
|
}
|
||||||
if len(xid) > 0 {
|
if len(xid) > 0 {
|
||||||
@ -130,79 +112,38 @@ func (server *Server) createVideoView(w http.ResponseWriter, r *http.Request) {
|
|||||||
vm.Status = int(v.Status)
|
vm.Status = int(v.Status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
renderCreateVideo(w, vm)
|
renderEditVideo(w, vm)
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderCreateVideo(w http.ResponseWriter, data any) {
|
// data
|
||||||
renderLayout(w, data, "web/templates/video/edit.html.tmpl")
|
|
||||||
|
// 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 {
|
// editVideo 视频编辑
|
||||||
Authorize
|
func (server *Server) editVideo(w http.ResponseWriter, r *http.Request) {
|
||||||
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) {
|
|
||||||
defer r.Body.Close()
|
defer r.Body.Close()
|
||||||
|
|
||||||
if err := r.ParseForm(); err != nil {
|
if err := r.ParseForm(); err != nil {
|
||||||
renderCreateVideo(w, videoCreateResp{Summary: "请求网络错误, 请刷新重试"})
|
renderEditVideo(w, videoEditPageData{Summary: "请求网络错误, 请刷新重试"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
vm, ok := viladatorCreateVedio(r)
|
vm, ok := viladatorEditVedio(r)
|
||||||
if !ok {
|
if !ok {
|
||||||
renderCreateVideo(w, vm)
|
renderEditVideo(w, vm)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,22 +163,34 @@ func (server *Server) createVideo(w http.ResponseWriter, r *http.Request) {
|
|||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
vm.Summary = "添加视频失败"
|
vm.Summary = "添加视频失败"
|
||||||
renderCreateVideo(w, vm)
|
renderEditVideo(w, vm)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} 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,
|
ID: vm.ID,
|
||||||
Title: vm.Title,
|
Title: vm.Title,
|
||||||
Description: vm.Description,
|
Description: vm.Description,
|
||||||
Images: vm.Images,
|
Images: vm.Images,
|
||||||
Status: int32(vm.Status),
|
Status: sta,
|
||||||
UpdateAt: curTime,
|
UpdateAt: curTime,
|
||||||
UpdateBy: u.Name,
|
UpdateBy: u.Name,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
vm.Summary = "更新视频失败"
|
vm.Summary = "更新视频失败"
|
||||||
renderCreateVideo(w, vm)
|
renderEditVideo(w, vm)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -245,25 +198,7 @@ func (server *Server) createVideo(w http.ResponseWriter, r *http.Request) {
|
|||||||
http.Redirect(w, r, "/me/videos", http.StatusFound)
|
http.Redirect(w, r, "/me/videos", http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
type transferData struct {
|
// transfer 视频转码
|
||||||
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")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (server *Server) transfer(w http.ResponseWriter, r *http.Request) {
|
func (server *Server) transfer(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
xid := vars["xid"]
|
xid := vars["xid"]
|
||||||
@ -318,3 +253,82 @@ func (server *Server) transfer(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
w.Write([]byte("视频正在转码中, 请稍后刷新页面"))
|
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)
|
||||||
|
*/
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
package convert
|
package convert
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/zhang2092/mediahls/internal/pkg/fileutil"
|
"github.com/zhang2092/mediahls/internal/pkg/fileutil"
|
||||||
|
"github.com/zhang2092/mediahls/internal/pkg/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ConvertHLS(savePath, filePath string) error {
|
func ConvertHLS(savePath, filePath string) error {
|
||||||
@ -20,18 +20,18 @@ func ConvertHLS(savePath, filePath string) error {
|
|||||||
|
|
||||||
binary, err := exec.LookPath("ffmpeg")
|
binary, err := exec.LookPath("ffmpeg")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("1: ", err)
|
logger.Logger.Errorf("exec look path ffmpeg: %v", err)
|
||||||
return 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
|
// 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"
|
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, " ")
|
args := strings.Split(command, " ")
|
||||||
cmd := exec.Command(binary, args...)
|
cmd := exec.Command(binary, args...)
|
||||||
_, err = cmd.Output()
|
_, err = cmd.Output()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("2: ", err)
|
logger.Logger.Errorf("ffmpeg cmd output: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +0,0 @@
|
|||||||
{{template "header" .}}
|
|
||||||
<div class="container">
|
|
||||||
<form id="form" enctype="multipart/form-data" action="/upload" method="POST">
|
|
||||||
<label for="avatar">请选择文件:</label><br>
|
|
||||||
<input type="file" id="file" name="file" /><br>
|
|
||||||
<button class="button" type="submit">提交</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
{{template "footer" .}}
|
|
||||||
@ -12,8 +12,8 @@
|
|||||||
<input type="email" name="email" class="form-control" required id="email" value="{{.Email}}"
|
<input type="email" name="email" class="form-control" required id="email" value="{{.Email}}"
|
||||||
aria-describedby="emailValid">
|
aria-describedby="emailValid">
|
||||||
</div>
|
</div>
|
||||||
{{if .EmailErr}}
|
{{if .EmailMsg}}
|
||||||
<small id="emailValid" style="color: #f44336;" class="form-text">{{.EmailErr}}</small>
|
<small id="emailValid" style="color: #f44336;" class="form-text">{{.EmailMsg}}</small>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -24,8 +24,8 @@
|
|||||||
<input type="password" name="password" class="form-control" required id="password" value="{{.Password}}"
|
<input type="password" name="password" class="form-control" required id="password" value="{{.Password}}"
|
||||||
aria-describedby="passwordValid">
|
aria-describedby="passwordValid">
|
||||||
</div>
|
</div>
|
||||||
{{if .PasswordErr}}
|
{{if .PasswordMsg}}
|
||||||
<small id="passwordValid" style="color: #f44336;" class="form-text">{{.PasswordErr}}</small>
|
<small id="passwordValid" style="color: #f44336;" class="form-text">{{.PasswordMsg}}</small>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-primary btn-block">提交</button>
|
<button type="submit" class="btn btn-primary btn-block">提交</button>
|
||||||
|
|||||||
@ -12,8 +12,8 @@
|
|||||||
<input type="email" name="email" class="form-control" required id="email" value="{{.Email}}"
|
<input type="email" name="email" class="form-control" required id="email" value="{{.Email}}"
|
||||||
aria-describedby="emailValid">
|
aria-describedby="emailValid">
|
||||||
</div>
|
</div>
|
||||||
{{if .EmailErr}}
|
{{if .EmailMsg}}
|
||||||
<small id="emailValid" style="color: #f44336;" class="form-text">{{.EmailErr}}</small>
|
<small id="emailValid" style="color: #f44336;" class="form-text">{{.EmailMsg}}</small>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -24,8 +24,8 @@
|
|||||||
<input type="text" name="username" class="form-control" required id="username" value="{{.Username}}"
|
<input type="text" name="username" class="form-control" required id="username" value="{{.Username}}"
|
||||||
aria-describedby="usernameValid">
|
aria-describedby="usernameValid">
|
||||||
</div>
|
</div>
|
||||||
{{if .UsernameErr}}
|
{{if .UsernameMsg}}
|
||||||
<small id="usernameValid" style="color: #f44336;" class="form-text">{{.UsernameErr}}</small>
|
<small id="usernameValid" style="color: #f44336;" class="form-text">{{.UsernameMsg}}</small>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -36,8 +36,8 @@
|
|||||||
<input type="password" name="password" class="form-control" required id="password" value="{{.Password}}"
|
<input type="password" name="password" class="form-control" required id="password" value="{{.Password}}"
|
||||||
aria-describedby="passwordValid">
|
aria-describedby="passwordValid">
|
||||||
</div>
|
</div>
|
||||||
{{if .PasswordErr}}
|
{{if .PasswordMsg}}
|
||||||
<small id="passwordValid" style="color: #f44336;" class="form-text">{{.PasswordErr}}</small>
|
<small id="passwordValid" style="color: #f44336;" class="form-text">{{.PasswordMsg}}</small>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<button type="submit" class="btn btn-primary btn-block">提交</button>
|
<button type="submit" class="btn btn-primary btn-block">提交</button>
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
<a href="/me/videos" class="btn btn-primary">返回列表</a>
|
<a href="/me/videos" class="btn btn-primary">返回列表</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-6 py-md-5 flex flex-column justify-content">
|
<div class="col-sm-6 py-md-5 flex flex-column justify-content">
|
||||||
<form action="/me/videos/create" method="post">
|
<form action="/me/videos/update" method="post">
|
||||||
{{if .ID}}
|
{{if .ID}}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
@ -26,8 +26,8 @@
|
|||||||
<input type="text" name="title" class="form-control" required id="title" value="{{.Title}}"
|
<input type="text" name="title" class="form-control" required id="title" value="{{.Title}}"
|
||||||
aria-describedby="titleValid">
|
aria-describedby="titleValid">
|
||||||
</div>
|
</div>
|
||||||
{{if .TitleErr}}
|
{{if .TitleMsg}}
|
||||||
<small id="titleValid" style="color: #f44336;" class="form-text">{{.TitleErr}}</small>
|
<small id="titleValid" style="color: #f44336;" class="form-text">{{.TitleMsg}}</small>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -37,15 +37,16 @@
|
|||||||
</div>
|
</div>
|
||||||
<input type="file" class="form-control" id="upload_images">
|
<input type="file" class="form-control" id="upload_images">
|
||||||
<input type="button" class="btn btn-secondary" value="上传" onclick="uploadImage()" />
|
<input type="button" class="btn btn-secondary" value="上传" onclick="uploadImage()" />
|
||||||
<input type="hidden" id="images" name="images" required value="{{.Images}}" aria-describedby="imagesValid">
|
<input type="hidden" id="images" name="images" required value="{{.Images}}"
|
||||||
|
aria-describedby="imagesValid">
|
||||||
</div>
|
</div>
|
||||||
<div class="image-box" style="margin-top: 8px;">
|
<div class="image-box" style="margin-top: 8px;">
|
||||||
{{if .Images}}
|
{{if .Images}}
|
||||||
<img width="120px" src="{{.Images}}" />
|
<img width="120px" src="{{.Images}}" />
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{if .ImagesErr}}
|
{{if .ImagesMsg}}
|
||||||
<small id="imagesValid" style="color: #f44336;" class="form-text">{{.ImagesErr}}</small>
|
<small id="imagesValid" style="color: #f44336;" class="form-text">{{.ImagesMsg}}</small>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -56,8 +57,8 @@
|
|||||||
<textarea class="form-control" id="description" name="description" required
|
<textarea class="form-control" id="description" name="description" required
|
||||||
aria-describedby="descriptionValid" rows="3">{{.Description}}</textarea>
|
aria-describedby="descriptionValid" rows="3">{{.Description}}</textarea>
|
||||||
</div>
|
</div>
|
||||||
{{if .DescriptionErr}}
|
{{if .DescriptionMsg}}
|
||||||
<small id="descriptionValid" style="color: #f44336;" class="form-text">{{.DescriptionErr}}</small>
|
<small id="descriptionValid" style="color: #f44336;" class="form-text">{{.DescriptionMsg}}</small>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@ -75,9 +76,30 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
<small id="upload_video_msg" style="color: #f44336;" class="form-text">
|
<small id="upload_video_msg" style="color: #f44336;" class="form-text">
|
||||||
{{.OriginLinkErr}}
|
{{.OriginLinkMsg}}
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
|
{{if eq .Status -1 200}}
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="input-group">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text">状态</span>
|
||||||
|
</div>
|
||||||
|
<select id="status" class="form-control" name="status">
|
||||||
|
{{if eq .Status 200}}
|
||||||
|
<option value="200" selected>正常</option>
|
||||||
|
{{else}}
|
||||||
|
<option value="200">正常</option>
|
||||||
|
{{end}}
|
||||||
|
{{if eq .Status -1}}
|
||||||
|
<option value="-1" selected>下架</option>
|
||||||
|
{{else}}
|
||||||
|
<option value="-1">下架</option>
|
||||||
|
{{end}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
<button type="submit" class="btn btn-primary">提交</button>
|
<button type="submit" class="btn btn-primary">提交</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,43 +0,0 @@
|
|||||||
{{template "header" .}}
|
|
||||||
<div class="container-fluid flex justify-content">
|
|
||||||
<div class="main">
|
|
||||||
<div class="title">
|
|
||||||
<h3>视频转码</h3>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h5>{{.Video.Title}}</h5>
|
|
||||||
<p>{{.Video.Description}}</p>
|
|
||||||
<p><img src="{{.Video.Images}}" width="120px" /></p>
|
|
||||||
{{if eq .Video.Status 0}}
|
|
||||||
<p>该视频需要转码才能播放</p>
|
|
||||||
<button id="transfer" class="btn btn-primary">转码</button>
|
|
||||||
{{else if eq .Video.Status 1}}
|
|
||||||
<p>转码中...</p>
|
|
||||||
{{else if eq .Video.Status 2}}
|
|
||||||
<p>转码失败, 请联系管理员</p>
|
|
||||||
{{else if eq .Video.Status 200}}
|
|
||||||
<p>恭喜您, 转码成功!</p>
|
|
||||||
{{end}}
|
|
||||||
<p id="msg"></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{define "js"}}
|
|
||||||
<script>
|
|
||||||
$('#transfer').click(function () {
|
|
||||||
let that = $(this)
|
|
||||||
that.attr("disable", true).html('转码中...')
|
|
||||||
$.ajax({
|
|
||||||
url: '/transfer/{{.Video.ID}}',
|
|
||||||
type: 'post',
|
|
||||||
success: function (obj) {
|
|
||||||
$('#msg').html(obj)
|
|
||||||
},
|
|
||||||
error: function (ex) {
|
|
||||||
console.log(ex)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{{end}}
|
|
||||||
{{template "footer" .}}
|
|
||||||
@ -3,7 +3,7 @@
|
|||||||
<div class="main">
|
<div class="main">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<h3>我的视频</h3>
|
<h3>我的视频</h3>
|
||||||
<a href="/me/videos/create" class="btn btn-primary">添加</a>
|
<a href="/me/videos/update" class="btn btn-primary">添加</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="video-list">
|
<div class="video-list">
|
||||||
{{range .Videos}}
|
{{range .Videos}}
|
||||||
@ -13,7 +13,7 @@
|
|||||||
<h5 class="card-title">{{.Title}}</h5>
|
<h5 class="card-title">{{.Title}}</h5>
|
||||||
<p class="card-text">{{.Description}}</p>
|
<p class="card-text">{{.Description}}</p>
|
||||||
|
|
||||||
<a href="/me/videos/create/{{.ID}}" class="btn btn-warning">编辑</a>
|
<a href="/me/videos/update/{{.ID}}" class="btn btn-warning">编辑</a>
|
||||||
<button id="del" data-id="{{.ID}}" class="btn btn-danger">删除</button>
|
<button id="del" data-id="{{.ID}}" class="btn btn-danger">删除</button>
|
||||||
|
|
||||||
{{if eq .Status 0}}
|
{{if eq .Status 0}}
|
||||||
Loading…
x
Reference in New Issue
Block a user