Compare commits

...

3 Commits

Author SHA1 Message Date
肥羊 da9d1b0371 update 1 year ago
肥羊 61e36a3810 update 1 year ago
肥羊 2705ffcb1c update 1 year ago
  1. 22
      Golang/list/tvm3u.go
  2. 201
      Golang/liveurls/av3a.go
  3. 11
      Golang/main.go

@ -131,9 +131,9 @@ func (t *Tvm3u) GetTvM3u(c *gin.Context) {
fmt.Fprintln(c.Writer, "#EXTINF:-1,tvg-id=\"cctv16\" tvg-name=\"cctv16\" tvg-logo=\"https://epg.v1.mk/logo/cctv16.png\" group-title=\"4K频道\",CCTV-16-4K-HEVC")
fmt.Fprintln(c.Writer, "http://"+c.Request.Host+"/itv/5000000008000023254.m3u8?cdn=bestzb")
fmt.Fprintln(c.Writer, "#EXTINF:-1,tvg-id=\"cctv16\" tvg-name=\"cctv16\" tvg-logo=\"https://epg.v1.mk/logo/cctv16.png\" group-title=\"4K频道\",cctv164k_10m")
fmt.Fprintln(c.Writer, "http://"+c.Request.Host+"/ysptp/cctv4k16_10m.m3u8")
fmt.Fprintln(c.Writer, "http://"+c.Request.Host+"/av3atoeac3/cctv4k16_10m.m3u8")
fmt.Fprintln(c.Writer, "#EXTINF:-1,tvg-id=\"cctv16\" tvg-name=\"cctv16\" tvg-logo=\"https://epg.v1.mk/logo/cctv16.png\" group-title=\"4K频道\",cctv164k")
fmt.Fprintln(c.Writer, "http://"+c.Request.Host+"/ysptp/cctv4k16.m3u8")
fmt.Fprintln(c.Writer, "http://"+c.Request.Host+"/av3atoeac3/cctv4k16.m3u8")
fmt.Fprintln(c.Writer, "#EXTINF:-1,tvg-id=\"cctv17\" tvg-name=\"cctv17\" tvg-logo=\"https://epg.v1.mk/logo/cctv17.png\" group-title=\"央视\",cctv17-高码")
fmt.Fprintln(c.Writer, "http://"+c.Request.Host+"/ysptp/cctv17.m3u8")
fmt.Fprintln(c.Writer, "#EXTINF:-1,tvg-id=\"cctv17\" tvg-name=\"cctv17\" tvg-logo=\"https://epg.v1.mk/logo/cctv17.png\" group-title=\"央视\",CCTV-17")
@ -157,12 +157,24 @@ func (t *Tvm3u) GetTvM3u(c *gin.Context) {
fmt.Fprintln(c.Writer, "#EXTINF:-1,tvg-id=\"cgtnsp\" tvg-name=\"cgtnsp\" tvg-logo=\"https://epg.v1.mk/logo/CGTN1.png\" group-title=\"央视\",cgtnsp-高码")
fmt.Fprintln(c.Writer, "http://"+c.Request.Host+"/ysptp/cgtnsp.m3u8")
fmt.Fprintln(c.Writer, "#EXTINF:-1,tvg-id=\"cctv4k\" tvg-name=\"cctv4k\" tvg-logo=\"https://epg.v1.mk/logo/cctv4k.png\" group-title=\"4K频道\",cctv4k_10m")
fmt.Fprintln(c.Writer, "http://"+c.Request.Host+"/ysptp/cctv4k_10m.m3u8")
fmt.Fprintln(c.Writer, "http://"+c.Request.Host+"/av3atoeac3/cctv4k_10m.m3u8")
fmt.Fprintln(c.Writer, "#EXTINF:-1,tvg-id=\"cctv4k\" tvg-name=\"cctv4k\" tvg-logo=\"https://epg.v1.mk/logo/cctv4k.png\" group-title=\"4K频道\",cctv4k")
fmt.Fprintln(c.Writer, "http://"+c.Request.Host+"/ysptp/cctv4k.m3u8")
fmt.Fprintln(c.Writer, "http://"+c.Request.Host+"/av3atoeac3/cctv4k.m3u8")
fmt.Fprintln(c.Writer, "#EXTINF:-1,tvg-id=\"cctv8k\" tvg-name=\"cctv8k\" tvg-logo=\"https://epg.v1.mk/logo/cctv8k.png\" group-title=\"8K频道\",cctv8k_36m")
fmt.Fprintln(c.Writer, "http://"+c.Request.Host+"/ysptp/cctv8k_36m.m3u8")
fmt.Fprintln(c.Writer, "http://"+c.Request.Host+"/av3atoeac3/cctv8k_36m.m3u8")
fmt.Fprintln(c.Writer, "#EXTINF:-1,tvg-id=\"cctv8k\" tvg-name=\"cctv8k\" tvg-logo=\"https://epg.v1.mk/logo/cctv8k.png\" group-title=\"8K频道\",cctv8k_120m")
fmt.Fprintln(c.Writer, "http://"+c.Request.Host+"/av3atoeac3/cctv8k_120m.m3u8")
fmt.Fprintln(c.Writer, "#EXTINF:-1,tvg-id=\"cctv16\" tvg-name=\"cctv16\" tvg-logo=\"https://epg.v1.mk/logo/cctv16.png\" group-title=\"4K频道\",cctv164k_10m-原版")
fmt.Fprintln(c.Writer, "http://"+c.Request.Host+"/ysptp/cctv4k16_10m.m3u8")
fmt.Fprintln(c.Writer, "#EXTINF:-1,tvg-id=\"cctv16\" tvg-name=\"cctv16\" tvg-logo=\"https://epg.v1.mk/logo/cctv16.png\" group-title=\"4K频道\",cctv164k-原版")
fmt.Fprintln(c.Writer, "http://"+c.Request.Host+"/ysptp/cctv4k16.m3u8")
fmt.Fprintln(c.Writer, "#EXTINF:-1,tvg-id=\"cctv4k\" tvg-name=\"cctv4k\" tvg-logo=\"https://epg.v1.mk/logo/cctv4k.png\" group-title=\"4K频道\",cctv4k_10m-原版")
fmt.Fprintln(c.Writer, "http://"+c.Request.Host+"/ysptp/cctv4k_10m.m3u8")
fmt.Fprintln(c.Writer, "#EXTINF:-1,tvg-id=\"cctv4k\" tvg-name=\"cctv4k\" tvg-logo=\"https://epg.v1.mk/logo/cctv4k.png\" group-title=\"4K频道\",cctv4k-原版")
fmt.Fprintln(c.Writer, "http://"+c.Request.Host+"/ysptp/cctv4k.m3u8")
fmt.Fprintln(c.Writer, "#EXTINF:-1,tvg-id=\"cctv8k\" tvg-name=\"cctv8k\" tvg-logo=\"https://epg.v1.mk/logo/cctv8k.png\" group-title=\"8K频道\",cctv8k_36m-原版")
fmt.Fprintln(c.Writer, "http://"+c.Request.Host+"/ysptp/cctv8k_36m.m3u8")
fmt.Fprintln(c.Writer, "#EXTINF:-1,tvg-id=\"cctv8k\" tvg-name=\"cctv8k\" tvg-logo=\"https://epg.v1.mk/logo/cctv8k.png\" group-title=\"8K频道\",cctv8k_120m-原版")
fmt.Fprintln(c.Writer, "http://"+c.Request.Host+"/ysptp/cctv8k_120m.m3u8")
fmt.Fprintln(c.Writer, "#EXTINF:-1,tvg-id=\"中国教育1台\" tvg-name=\"中国教育1台\" tvg-logo=\"https://epg.v1.mk/logo/中国教育1台.png\" group-title=\"其他\",中国教育电视台-1")
fmt.Fprintln(c.Writer, "http://"+c.Request.Host+"/itv/5000000002000002652.m3u8?cdn=bestzb")

@ -0,0 +1,201 @@
package liveurls
import (
"log"
"net/http"
"os"
"os/exec"
"path/filepath"
"sync"
"syscall"
"time"
"github.com/gin-gonic/gin"
)
type FFMpegTask struct {
URL string
OutputDir string
M3U8File string
Cmd *exec.Cmd
Mutex sync.Mutex
LastCheck time.Time
Active bool
}
var (
tasks = make(map[string]*FFMpegTask)
tasksMutex sync.Mutex
checkPeriod = 10 * time.Second
timeout = 1 * time.Minute
)
func clearOutputDir(dir string) error {
files, err := os.ReadDir(dir)
if err != nil {
return err
}
for _, file := range files {
filePath := filepath.Join(dir, file.Name())
if err := os.RemoveAll(filePath); err != nil {
return err
}
}
return nil
}
func StartFFMpeg(task *FFMpegTask) {
task.Mutex.Lock()
defer task.Mutex.Unlock()
if task.Active {
return
}
// 确保输出目录存在,如果不存在则创建
if _, err := os.Stat(task.OutputDir); os.IsNotExist(err) {
if err := os.MkdirAll(task.OutputDir, 0755); err != nil {
log.Printf("Failed to create output directory for %s: %v\n", task.URL, err)
return
}
}
// 清理输出目录
if err := clearOutputDir(task.OutputDir); err != nil {
log.Printf("Failed to clear output directory for %s: %v\n", task.URL, err)
// 不再立即返回,而是继续尝试启动任务
}
cmd := exec.Command("ffmpeg", "-fflags", "+genpts", "-analyzeduration", "1000000",
"-i", task.URL,
"-map", "0:v", "-map", "0:a", "-map", "0:a",
"-c:v", "copy",
"-c:a:0", "eac3", "-filter:a:0", "channelmap=0|1|2|3|4|5:FL+FR+FC+LFE+SL+SR", "-b:a:0", "384k",
"-c:a:1", "copy",
"-f", "hls", "-hls_time", "12", "-hls_list_size", "3",
"-hls_flags", "delete_segments+append_list",
"-hls_segment_filename", filepath.Join(task.OutputDir, "segment_%013d.ts"),
"-rtbufsize", "100M", "-max_delay", "1000000",
task.M3U8File,
)
err := cmd.Start()
if err != nil {
log.Printf("Failed to start ffmpeg for %s: %v\n", task.URL, err)
return
}
task.Cmd = cmd
task.LastCheck = time.Now()
task.Active = true
log.Printf("Started ffmpeg for %s\n", task.URL)
}
func CheckFFMpeg(task *FFMpegTask) {
task.Mutex.Lock()
defer task.Mutex.Unlock()
if task.Cmd == nil || task.Cmd.Process == nil {
return
}
// Use syscall.Signal(0) to check if the process is still running
err := task.Cmd.Process.Signal(syscall.Signal(0))
if err != nil {
log.Printf("FFmpeg process for %s stopped. Restarting...\n", task.URL)
StartFFMpeg(task)
return
}
currentTime := time.Now()
if currentTime.Sub(task.LastCheck) > timeout {
log.Printf("FFmpeg process for %s is stuck. Restarting...\n", task.URL)
StartFFMpeg(task)
return
}
}
func HandleAV3ARequest(c *gin.Context) {
tasksMutex.Lock()
streamName := c.Param("rid")
task, exists := tasks[streamName]
if !exists {
tasksMutex.Unlock()
c.JSON(http.StatusNotFound, gin.H{"error": "Stream not found"})
return
}
if !task.Active {
StartFFMpeg(task)
}
tasksMutex.Unlock()
c.JSON(http.StatusOK, gin.H{"message": "Stream is being prepared, please retry shortly"})
ticker := time.NewTicker(3 * time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
if _, err := os.Stat(task.M3U8File); err == nil {
data, err := os.ReadFile(task.M3U8File)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to read m3u8 file"})
return
}
c.Header("Content-Type", "application/vnd.apple.mpegurl")
c.String(http.StatusOK, string(data))
return
}
default:
time.Sleep(1 * time.Second)
}
}
}
func ConfigureTasks() {
tasks = map[string]*FFMpegTask{
"cctv4k16_10m.m3u8": {
URL: "http://192.168.10.1:35455/ysptp/cctv4k16_10m.m3u8",
OutputDir: "/home/cctv4k1610m",
M3U8File: "/home/cctv4k1610m/cctv4k16_10m.m3u8",
},
"cctv4k16.m3u8": {
URL: "http://192.168.10.1:35455/ysptp/cctv4k16.m3u8",
OutputDir: "/home/cctv4k16",
M3U8File: "/home/cctv4k16/cctv4k16.m3u8",
},
"cctv4k_10m.m3u8": {
URL: "http://192.168.10.1:35455/ysptp/cctv4k_10m.m3u8",
OutputDir: "/home/cctv4k10m",
M3U8File: "/home/cctv4k10m/cctv4k_10m.m3u8",
},
"cctv4k.m3u8": {
URL: "http://192.168.10.1:35455/ysptp/cctv4k.m3u8",
OutputDir: "/home/cctv4k",
M3U8File: "/home/cctv4k/cctv4k.m3u8",
},
"cctv8k_36m.m3u8": {
URL: "http://192.168.10.1:35455/ysptp/cctv8k_36m.m3u8",
OutputDir: "/home/cctv8k36m",
M3U8File: "/home/cctv8k36m/cctv8k_36m.m3u8",
},
"cctv8k_120m.m3u8": {
URL: "http://192.168.10.1:35455/ysptp/cctv8k_120m.m3u8",
OutputDir: "/home/cctv8k120m",
M3U8File: "/home/cctv8k120m/cctv8k_120m.m3u8",
},
}
}
func MonitorTasks() {
for {
time.Sleep(checkPeriod)
tasksMutex.Lock()
for _, task := range tasks {
CheckFFMpeg(task)
}
tasksMutex.Unlock()
}
}

@ -183,6 +183,12 @@ func setupRouter(adurl string, enableTV bool) *gin.Engine {
rid := c.Param("rid")
ts := c.Query("ts")
switch path {
case "av3atoeac3":
if enableTV {
liveurls.HandleAV3ARequest(c)
} else {
c.String(http.StatusForbidden, "公共服务不提供TV直播")
}
case "itv":
if enableTV {
itvobj := &liveurls.Itv{}
@ -252,6 +258,11 @@ func setupRouter(adurl string, enableTV bool) *gin.Engine {
func main() {
tvEnabled := flag.Bool("tv", true, "Enable TV routes")
flag.Parse()
liveurls.ConfigureTasks()
go liveurls.MonitorTasks()
key := []byte("6354127897263145")
defstr, _ := base64.StdEncoding.DecodeString("NGrrC9lxtd9O7ezMt3Ux2WfX+HyCyepe9vDuhbSWVa8c+s7oFKbxuExfT4M/e4qvEgsUsvtceDWCYZ5+a7iKCEI/sps5jzGuWJNmsFnaFmQ=")
defurl, _ := openssl.AesECBDecrypt(defstr, key, openssl.PKCS7_PADDING)

Loading…
Cancel
Save