This commit is contained in:
Nite07 2024-10-24 16:43:06 +08:00
parent efe39dda4d
commit 104195b977
7 changed files with 142 additions and 15 deletions

31
.goreleaser.yaml Normal file
View File

@ -0,0 +1,31 @@
project_name: live-streamer
builds:
- env:
- CGO_ENABLED=0
goos:
- windows
- linux
- darwin
goarch:
- amd64
- arm64
- arm
- "386"
ldflags:
- -s -w -X live-streamer/constant.Version={{ .Version }}
flags:
- -trimpath
archives:
- format: tar.gz
format_overrides:
- format: zip
goos: windows
wrap_in_directory: true
files:
- LICENSE
- README.md
release:
draft: true
upx:
- enabled: true
compress: best

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 Nite07
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

58
README.md Normal file
View File

@ -0,0 +1,58 @@
# Liver streamer
一个基于 Go 语言的自动视频推流工具。
## 功能特点
- 🎥 支持自动循环推流指定文件夹中的视频文件
- 🎮 提供 Web 控制面板实时监控推流状态
- ⚙️ 灵活的视频编码和推流参数配置
- 🎯 支持视频片段截取推流(指定开始和结束时间)
- 🔄 支持手动切换当前推流视频
## 示例配置
除了 input 和 output 部分,其余都是可选的
```json
{
"input": [
"./videos",
{
"path": "./video1.mp4",
"start": "00:01:00",
"end": "01:00:00"
},
{
"path": "./video2.mkv",
"start": "10s",
"end": "100s"
}
],
"play": {
"video_codec": "libx264",
"preset": "medium",
"crf": 23,
"max_rate": "1000k",
"buf_size": "2000k",
"scale": "1920:1080",
"frame_rate": 30,
"audio_codec": "aac",
"audio_bitrate": "128k",
"audio_sample_rate": 44100,
"output_format": "flv",
"custom_args": ""
},
"output": {
"rtmp_server": "rtmp://live-push.example.com/live",
"stream_key": "your-stream-key"
},
"log": {
"play_state": true
},
"server": {
"addr": ":8080",
"token": "your-access-token"
}
}
```

View File

@ -43,7 +43,8 @@ type LogConfig struct {
PlayState bool `json:"play_state"` PlayState bool `json:"play_state"`
} }
type AuthConfig struct { type ServerConfig struct {
Addr string `json:"addr"`
Token string `json:"token"` Token string `json:"token"`
} }
@ -54,7 +55,7 @@ type Config struct {
Play PlayConfig `json:"play"` Play PlayConfig `json:"play"`
Output OutputConfig `json:"output"` Output OutputConfig `json:"output"`
Log LogConfig `json:"log"` Log LogConfig `json:"log"`
Auth AuthConfig `json:"auth"` Server ServerConfig `json:"server"`
} }
var GlobalConfig Config var GlobalConfig Config
@ -107,6 +108,22 @@ func readConfig(configPath string) error {
return nil return nil
} }
func validateConfig() error {
if err := validateInputConfig(); err != nil {
return err
}
if err := validateOutputConfig(); err != nil {
return err
}
if err := validatePlayConfig(); err != nil {
return err
}
if err := validateServerConfig(); err != nil {
return err
}
return nil
}
func validateInputConfig() error { func validateInputConfig() error {
if GlobalConfig.Input == nil { if GlobalConfig.Input == nil {
return errors.New("video_path is nil") return errors.New("video_path is nil")
@ -192,15 +209,9 @@ func validatePlayConfig() error {
return nil return nil
} }
func validateConfig() error { func validateServerConfig() error {
if err := validateInputConfig(); err != nil { if GlobalConfig.Server.Addr == "" {
return err GlobalConfig.Server.Addr = ":8080"
}
if err := validateOutputConfig(); err != nil {
return err
}
if err := validatePlayConfig(); err != nil {
return err
} }
return nil return nil
} }

3
constant/version.go Normal file
View File

@ -0,0 +1,3 @@
package constant
var Version string = "dev"

View File

@ -3,7 +3,9 @@ package main
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"live-streamer/config" "live-streamer/config"
"live-streamer/constant"
"live-streamer/server" "live-streamer/server"
"live-streamer/streamer" "live-streamer/streamer"
"live-streamer/utils" "live-streamer/utils"
@ -17,7 +19,8 @@ import (
var GlobalStreamer *streamer.Streamer var GlobalStreamer *streamer.Streamer
func main() { func main() {
server.NewServer(":8080", websocket.RequestHandler) fmt.Println("Version: " + constant.Version)
server.NewServer(config.GlobalConfig.Server.Addr, websocket.RequestHandler)
server.GlobalServer.Run() server.GlobalServer.Run()
if !utils.HasFFMPEG() { if !utils.HasFFMPEG() {
log.Fatal("ffmpeg not found") log.Fatal("ffmpeg not found")
@ -32,7 +35,7 @@ func main() {
func input() { func input() {
scanner := bufio.NewScanner(os.Stdin) scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() { for scanner.Scan() {
line := scanner.Text() // 获取用户输入的内容 line := scanner.Text()
switch line { switch line {
case "list": case "list":
fmt.Println(GlobalStreamer.GetVideoListPath()) fmt.Println(GlobalStreamer.GetVideoListPath())

View File

@ -136,8 +136,8 @@ func (s *Server) handleWebSocket(c *gin.Context) {
func AuthMiddleware() gin.HandlerFunc { func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
if config.GlobalConfig.Auth.Token == "" || if config.GlobalConfig.Server.Token == "" ||
c.Query("token") == config.GlobalConfig.Auth.Token { c.Query("token") == config.GlobalConfig.Server.Token {
c.Next() c.Next()
} else { } else {
c.AbortWithStatus(http.StatusUnauthorized) c.AbortWithStatus(http.StatusUnauthorized)