结合us3
This commit is contained in:
parent
7dffb72bfe
commit
dc1dad08f4
@ -5,4 +5,4 @@ Website = "https://iteay.top"
|
||||
Name = "HLS-builder"
|
||||
ID = "top.iteay.hls-builder"
|
||||
Version = "1.0.0"
|
||||
Build = 6
|
||||
Build = 24
|
||||
|
BIN
bin/.DS_Store
vendored
Normal file
BIN
bin/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
bin/us3cli-mac
Executable file
BIN
bin/us3cli-mac
Executable file
Binary file not shown.
BIN
bin/us3cli-windows.exe
Executable file
BIN
bin/us3cli-windows.exe
Executable file
Binary file not shown.
6
config/userconfig.yaml
Normal file
6
config/userconfig.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
accesskey: "TOKEN_f7c84db0-1671-4a70-953e-558cb25a4d74"
|
||||
secretkey: "7de3463e-0ad8-4f28-ba26-b5012f78f2dc"
|
||||
endpoint: "ufile.cn-bj.ucloud.cn"
|
||||
encrypt: "false"
|
||||
enablessl: "true"
|
||||
language: "ZH"
|
10
fyne-cross.toml
Normal file
10
fyne-cross.toml
Normal file
@ -0,0 +1,10 @@
|
||||
[build]
|
||||
# 目标操作系统和架构
|
||||
targets = ["windows/amd64", "darwin/amd64", "linux/amd64"]
|
||||
icon = "icon.png"
|
||||
|
||||
[package]
|
||||
# 应用的唯一标识符
|
||||
id = "top.iteay.hls-builder"
|
||||
# 打包的资源文件目录
|
||||
resources = ["bin", "font"]
|
BIN
fyne-cross/.DS_Store
vendored
BIN
fyne-cross/.DS_Store
vendored
Binary file not shown.
BIN
fyne-cross/bin/.DS_Store
vendored
BIN
fyne-cross/bin/.DS_Store
vendored
Binary file not shown.
BIN
fyne-cross/bin/darwin-amd64/hls-builder
Executable file
BIN
fyne-cross/bin/darwin-amd64/hls-builder
Executable file
Binary file not shown.
Binary file not shown.
BIN
fyne-cross/dist/.DS_Store
vendored
Normal file
BIN
fyne-cross/dist/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
fyne-cross/dist/darwin-amd64/.DS_Store
vendored
Normal file
BIN
fyne-cross/dist/darwin-amd64/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
fyne-cross/dist/windows-amd64/HLS-builder.exe.zip
vendored
BIN
fyne-cross/dist/windows-amd64/HLS-builder.exe.zip
vendored
Binary file not shown.
BIN
fyne-cross/tmp/darwin-amd64/Icon.png
Executable file
BIN
fyne-cross/tmp/darwin-amd64/Icon.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
5
go.mod
5
go.mod
@ -2,7 +2,10 @@ module hls-builder
|
||||
|
||||
go 1.22.0
|
||||
|
||||
require fyne.io/fyne/v2 v2.4.5
|
||||
require (
|
||||
fyne.io/fyne/v2 v2.4.5
|
||||
github.com/google/uuid v1.1.2
|
||||
)
|
||||
|
||||
require (
|
||||
fyne.io/systray v1.10.1-0.20231115130155-104f5ef7839e // indirect
|
||||
|
1
go.sum
1
go.sum
@ -160,6 +160,7 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe
|
||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
|
@ -1,34 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleName</key>
|
||||
<string>hls-builder</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>hls-builder</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.example.hls-builder</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>icon.icns</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.0.1</string>
|
||||
<key>CFBundleSupportedPlatforms</key>
|
||||
<array>
|
||||
<string>MacOSX</string>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true/>
|
||||
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
||||
<true/>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.11</string>
|
||||
</dict>
|
||||
</plist>
|
Binary file not shown.
Binary file not shown.
149
main.go
149
main.go
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* @Author: BlackTeay
|
||||
* @Date: 2024-04-30 09:37:39
|
||||
* @LastEditTime: 2024-05-06 09:38:30
|
||||
* @LastEditTime: 2024-05-06 16:37:14
|
||||
* @LastEditors: BlackTeay
|
||||
* @Description:
|
||||
* @FilePath: /hls_builder/main.go
|
||||
@ -11,13 +11,16 @@ package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"embed"
|
||||
_ "embed"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image/color"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
@ -30,11 +33,15 @@ import (
|
||||
"fyne.io/fyne/v2/storage"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
//go:embed "font/NotoSansSC-Regular.ttf"
|
||||
var ttfBytes []byte
|
||||
|
||||
//go:embed bin/*
|
||||
var ffmpegFS embed.FS
|
||||
|
||||
type MyTheme struct{}
|
||||
|
||||
func (MyTheme) Color(c fyne.ThemeColorName, v fyne.ThemeVariant) color.Color {
|
||||
@ -53,21 +60,62 @@ func (MyTheme) Size(s fyne.ThemeSizeName) float32 {
|
||||
return theme.DefaultTheme().Size(s)
|
||||
}
|
||||
func getFFmpegPath() string {
|
||||
var path string
|
||||
var ffmpegFileName string
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
path = "bin/ffmpeg_windows.exe"
|
||||
case "linux":
|
||||
path = "bin/ffmpeg_linux"
|
||||
ffmpegFileName = "ffmpeg_windows.exe"
|
||||
case "darwin":
|
||||
path = "bin/ffmpeg_darwin"
|
||||
default:
|
||||
log.Fatalf("Unsupported operating system: %s", runtime.GOOS)
|
||||
ffmpegFileName = "ffmpeg_darwin"
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
// 读取文件内容
|
||||
data, err := ffmpegFS.ReadFile("bin/" + ffmpegFileName)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// 写入到临时文件中
|
||||
tmpDir, err := os.MkdirTemp("", "ffmpeg")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
tmpFilePath := filepath.Join(tmpDir, ffmpegFileName)
|
||||
if err := os.WriteFile(tmpFilePath, data, 0755); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return tmpFilePath
|
||||
}
|
||||
func getUs3cliPath() string {
|
||||
var us3cliFileName string
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
us3cliFileName = "us3cli-windows.exe"
|
||||
case "darwin":
|
||||
us3cliFileName = "us3cli-mac"
|
||||
}
|
||||
|
||||
// 读取文件内容
|
||||
data, err := ffmpegFS.ReadFile("bin/" + us3cliFileName)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// 写入到临时文件中
|
||||
tmpDir, err := os.MkdirTemp("", "us3cli")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
tmpFilePath := filepath.Join(tmpDir, us3cliFileName)
|
||||
if err := os.WriteFile(tmpFilePath, data, 0755); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return tmpFilePath
|
||||
}
|
||||
func main() {
|
||||
//打印程序当前路径
|
||||
log.Println("Current path:", os.Getenv("PWD"))
|
||||
myApp := app.NewWithID("hls_builder")
|
||||
myApp.Settings().SetTheme(MyTheme{})
|
||||
myWindow := myApp.NewWindow("HLS-builder 视频切片工具")
|
||||
@ -102,6 +150,8 @@ func main() {
|
||||
}, myWindow)
|
||||
})
|
||||
var btnSlice *widget.Button // 预先声明btnSlice变量
|
||||
var randDir string
|
||||
var hlsDir string
|
||||
btnSlice = widget.NewButton("开始切片", func() {
|
||||
if inputFile.Text == "没有选择视频文件" || outputDir.Text == "没有选择输出路径" {
|
||||
dialog.ShowError(errors.New("请选择视频文件和输出路径"), myWindow)
|
||||
@ -114,7 +164,16 @@ func main() {
|
||||
btnSlice.Disable()
|
||||
btnSlice.SetText("切片中...")
|
||||
|
||||
go sliceVideo(inputFile.Text, outputDir.Text, progressBar, func() {
|
||||
randDir = uuid.New().String()
|
||||
//在outputDir中创建一个文件夹,名为一个UUID字符串
|
||||
hlsDir = outputDir.Text + "/" + randDir
|
||||
//新建这个目录
|
||||
err := os.Mkdir(hlsDir, 0755)
|
||||
if err != nil {
|
||||
dialog.ShowError(errors.New("建立随机目录出错!"), myWindow)
|
||||
}
|
||||
|
||||
go sliceVideo(inputFile.Text, hlsDir, progressBar, func() {
|
||||
// UI updates directly in the callback
|
||||
btnSelectFile.Enable()
|
||||
btnSelectOutput.Enable()
|
||||
@ -125,7 +184,14 @@ func main() {
|
||||
}, btnSelectFile, btnSelectOutput, btnSlice, myWindow)
|
||||
|
||||
})
|
||||
|
||||
uploadLabel := widget.NewLabel("上传切片到Ucloud")
|
||||
var btnUpload *widget.Button
|
||||
btnUpload = widget.NewButton("上传到服务器", func() {
|
||||
go upload(hlsDir, randDir, func() {
|
||||
btnUpload.Enable()
|
||||
})
|
||||
})
|
||||
// btnUpload.Disable()
|
||||
content := container.NewVBox(
|
||||
inputFile,
|
||||
btnSelectFile,
|
||||
@ -133,6 +199,8 @@ func main() {
|
||||
btnSelectOutput,
|
||||
progressBar,
|
||||
btnSlice,
|
||||
uploadLabel,
|
||||
btnUpload,
|
||||
)
|
||||
|
||||
myWindow.SetContent(content)
|
||||
@ -152,7 +220,7 @@ func sliceVideo(inputFile, outputDir string, progressBar *widget.ProgressBar, on
|
||||
"-hls_time", "5", // 每个 HLS 段的最大时长(秒)
|
||||
"-hls_list_size", "0", // 播放列表中的最大段数,0表示无限制
|
||||
"-f", "hls", // 输出格式为 HLS
|
||||
"-hls_segment_filename", outputDir+"/%04d.ts", // 段文件的命名方式
|
||||
"-hls_segment_filename", outputDir+"/%08d.ts", // 段文件的命名方式
|
||||
outputDir+"/playlist.m3u8", // 输出的 m3u8 文件位置
|
||||
)
|
||||
// cmd.Stderr = os.Stderr // 将 stderr 直接定向到系统的 stderr,以便直接调试 FFmpeg 的输出
|
||||
@ -191,10 +259,10 @@ func sliceVideo(inputFile, outputDir string, progressBar *widget.ProgressBar, on
|
||||
progressBar.SetValue(1.0) // 设置进度条到最大值
|
||||
fyne.CurrentApp().SendNotification(&fyne.Notification{
|
||||
Title: "HLS-builder 视频切片工具",
|
||||
Content: fmt.Sprintf("✅ 视频切片完成! 总用时: %s", formattedDuration),
|
||||
Content: fmt.Sprintf("✅ 视频切片完成! 总用时: %s\n存储位置:%s", formattedDuration, outputDir),
|
||||
})
|
||||
|
||||
dialog.ShowInformation("完成", fmt.Sprintf("✅ 视频切片完成! 总用时: %s", formattedDuration), myWindow)
|
||||
dialog.ShowInformation("完成", fmt.Sprintf("✅ 视频切片完成! 总用时: %s\n存储位置:%s", formattedDuration, outputDir), myWindow)
|
||||
|
||||
log.Println("视频切片完成")
|
||||
break
|
||||
@ -292,3 +360,54 @@ func formatDuration(d time.Duration) string {
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// 上传到Ucloud
|
||||
func upload(localPath string, keyPath string, onComplete func()) {
|
||||
fmt.Println("上传到Ucloud")
|
||||
fmt.Println("localPath:", localPath)
|
||||
fmt.Println("keyPath:", keyPath)
|
||||
|
||||
us3cliPath := getUs3cliPath()
|
||||
bucket := "us3://jlntv-live/replay/" + keyPath
|
||||
|
||||
cmd := exec.Command(us3cliPath, "cp", localPath, bucket, "-r", "--parallel", "10", "--reduce")
|
||||
|
||||
// 获取命令的标准输出和错误输出
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
log.Fatal("Error creating stdout pipe:", err)
|
||||
}
|
||||
stderr, err := cmd.StderrPipe()
|
||||
if err != nil {
|
||||
log.Fatal("Error creating stderr pipe:", err)
|
||||
}
|
||||
|
||||
// 开始执行命令
|
||||
if err := cmd.Start(); err != nil {
|
||||
log.Fatalf("Failed to start command: %s", err)
|
||||
}
|
||||
|
||||
// 使用协程异步读取输出
|
||||
go func() {
|
||||
scanner := bufio.NewScanner(stdout)
|
||||
for scanner.Scan() {
|
||||
fmt.Println("STDOUT:", scanner.Text())
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
scanner := bufio.NewScanner(stderr)
|
||||
for scanner.Scan() {
|
||||
fmt.Println("STDERR:", scanner.Text())
|
||||
}
|
||||
}()
|
||||
|
||||
// 等待命令执行完成
|
||||
if err := cmd.Wait(); err != nil {
|
||||
log.Printf("Command finished with error: %v", err)
|
||||
}
|
||||
|
||||
if onComplete != nil {
|
||||
onComplete()
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user