【Golang】FFmpeg 实现切片播放,倍速播放,在线截图,截取视频

package main

// import (
// 	"fmt"
// 	"os"
// 	"os/exec"
// 	"path/filepath"
// )

// func main() {
// 	inputFile := "./test.mp4" // 输入视频文件
// 	outputDir := "output"     // 输出目录
// 	segmentDuration := "10"   // 每个分片的时长(秒)

// 	// 创建输出目录
// 	err := os.MkdirAll(outputDir, os.ModePerm)
// 	if err != nil {
// 		fmt.Printf("创建输出目录失败: %v\n", err)
// 		return
// 	}

// 	// 构建FFmpeg命令
// 	outputPattern := filepath.Join(outputDir, "segment_%03d.ts")
// 	cmd := exec.Command("ffmpeg",
// 		"-i", inputFile,
// 		"-c:v", "libx264",
// 		"-c:a", "aac",
// 		"-f", "segment",
// 		"-segment_time", segmentDuration,
// 		"-segment_format", "mpegts",
// 		"-segment_list", filepath.Join(outputDir, "playlist.m3u8"),
// 		"-segment_list_type", "m3u8",
// 		outputPattern)

// 	// 执行FFmpeg命令
// 	output, err := cmd.CombinedOutput()
// 	if err != nil {
// 		fmt.Printf("视频切片失败: %v\n", err)
// 		fmt.Println(string(output))
// 		return
// 	}

// 	fmt.Println("视频切片完成!")
// }

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
)

const (
	inputFile       = "./extended.mp4"
	outputDir       = "output"
	segmentDuration = "10"
	serverPort      = ":8999"
)

func main() {
	// 确保输出目录存在
	err := os.MkdirAll(outputDir, os.ModePerm)
	if err != nil {
		log.Fatalf("创建输出目录失败: %v\n", err)
	}

	// 复制原始MP4文件到输出目录
	err = copyFile(inputFile, filepath.Join(outputDir, "original.mp4"))
	if err != nil {
		log.Fatalf("复制原始文件失败: %v\n", err)
	}

	// 执行视频切片
	err = sliceVideo()
	if err != nil {
		log.Fatalf("视频切片失败: %v\n", err)
	}

	// 设置静态文件服务
	http.Handle("/output/", http.StripPrefix("/output/", http.FileServer(http.Dir(outputDir))))

	// 设置首页
	http.HandleFunc("/", serveIndex)

	fmt.Printf("服务器启动在 http://localhost%s\n", serverPort)
	log.Fatal(http.ListenAndServe(serverPort, nil))
}

func copyFile(src, dst string) error {
	input, err := os.ReadFile(src)
	if err != nil {
		return err
	}

	return os.WriteFile(dst, input, 0644)
}

func sliceVideo() error {
	outputPattern := filepath.Join(outputDir, "segment_%03d.ts")
	cmd := exec.Command("ffmpeg",
		"-i", inputFile,
		"-c:v", "libx264",
		"-c:a", "aac",
		"-f", "segment",
		"-segment_time", segmentDuration,
		"-segment_format", "mpegts",
		"-segment_list", filepath.Join(outputDir, "playlist.m3u8"),
		"-segment_list_type", "m3u8",
		outputPattern)

	output, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("ffmpeg 命令执行失败: %v\n%s", err, output)
	}

	return nil
}

func serveIndex(w http.ResponseWriter, r *http.Request) {
	html := `
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>视频测试</title>
    <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
    <style>
        body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
        h2 { color: #333; }
        video { max-width: 100%; }
    </style>
</head>
<body>
    <h1>视频测试页面</h1>

    <h2>1. 原始 MP4 视频</h2>
    <video id="mp4Video" controls>
        <source src="/output/original.mp4" type="video/mp4">
        您的浏览器不支持 video 标签。
    </video>

    <h2>2. HLS 流 (m3u8)</h2>
    <video id="hlsVideo" controls></video>

    <script>
        var video = document.getElementById('hlsVideo');
        if(Hls.isSupported()) {
            var hls = new Hls();
            hls.loadSource('/output/playlist.m3u8');
            hls.attachMedia(video);
            hls.on(Hls.Events.MANIFEST_PARSED, function() {
                video.play();
            });
        }
        else if (video.canPlayType('application/vnd.apple.mpegurl')) {
            video.src = '/output/playlist.m3u8';
            video.addEventListener('loadedmetadata', function() {
                video.play();
            });
        }
    </script>
</body>
</html>
`
	fmt.Fprint(w, html)
}

问题:在本地localhost访问网站mp4不同时间点视频跳转比ts快,在卡顿卡死也不重新请求新的ts

解决

// FILEPATH: /usr/local/vid/slice_vid/main.go

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
)

const (
	inputFile       = "./extended.mp4"
	outputDir       = "output"
	segmentDuration = "4" // 减小分片大小到 4 秒
	serverPort      = ":8999"
)

func main() {
	 // 确保输出目录存在
	 err := os.MkdirAll(outputDir, os.ModePerm)
	 if err != nil {
	 	log.Fatalf("创建输出目录失败: %v\n", err)
	 }

	 // 复制原始MP4文件到输出目录
	 err = copyFile(inputFile, filepath.Join(outputDir, "original.mp4"))
	 if err != nil {
	 	log.Fatalf("复制原始文件失败: %v\n", err)
	 }

	 // 执行视频切片
	 err = sliceVideo()
	 if err != nil {
	 	log.Fatalf("视频切片失败: %v\n", err)
	 }

	// 设置静态文件服务
	http.Handle("/output/", http.StripPrefix("/output/", http.FileServer(http.Dir(outputDir))))

	// 设置首页
	http.HandleFunc("/", serveIndex)

	fmt.Printf("服务器启动在 http://localhost%s\n", serverPort)
	log.Fatal(http.ListenAndServe(serverPort, nil))
}

func copyFile(src, dst string) error {
	input, err := os.ReadFile(src)
	if err != nil {
		return err
	}

	return os.WriteFile(dst, input, 0644)
}

func sliceVideo() error {
	outputPattern := filepath.Join(outputDir, "segment_%03d.ts")
	cmd := exec.Command("ffmpeg",
		"-i", inputFile,
		"-c:v", "libx264",
		"-preset", "veryfast",
		"-crf", "23",
		"-g", "48",
		"-keyint_min", "48", // 强制最小关键帧间隔
		"-sc_threshold", "0", // 禁用场景切换检测
		"-c:a", "aac",
		"-b:a", "128k",
		"-ac", "2",
		"-f", "segment",
		"-segment_time", segmentDuration,
		"-segment_format", "mpegts",
		"-segment_list", filepath.Join(outputDir, "playlist.m3u8"),
		"-segment_list_type", "m3u8",
		"-force_key_frames", "expr:gte(t,n_forced*4)", // 每 4 秒强制一个关键帧
		outputPattern)

	output, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("ffmpeg 命令执行失败: %v\n%s", err, output)
	}

	return nil
}

func serveIndex(w http.ResponseWriter, r *http.Request) {
	html := `
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>HLS 视频播放</title>
    <!-- 引入 hls.js 库 -->
    <script type="text/javascript" src="https://cdn.jsdelivr.net/hls.js/latest/hls.min.js"></script>
</head>
<body>
    <!-- 视频播放容器 -->
    <video class="video" id="HLSPlayer" controls>
        <!-- 如果浏览器支持 HLS,这里会显示视频 -->
        <p>您的浏览器不支持 HLS 视频播放,请升级浏览器或使用支持 HLS 的设备。</p>
    </video>

    <script>
        // 获取视频播放器元素
        let video = document.getElementById("HLSPlayer");

        // HLS 视频流的 URL(请替换为你的 m3u8 文件路径)
        var url = '/output/playlist.m3u8';  // 替换为你的 HLS 流地址

        // 检查浏览器是否支持 HLS
        if (Hls.isSupported()) {
            // 创建 HLS 实例
            var hls = new Hls();
            hls.loadSource(url);  // 加载 HLS 流
            hls.attachMedia(video);  // 将 HLS 实例绑定到 video 元素
            hls.on(Hls.Events.MANIFEST_PARSED, function () {
                video.play();  // 当 HLS 流解析完成后自动播放
            });

            // 错误处理
            hls.on(Hls.Events.ERROR, function (event, data) {
                if (data.fatal) {
                    switch (data.type) {
                        case Hls.ErrorTypes.NETWORK_ERROR:
                            console.log("网络错误,尝试重新加载...");
                            hls.startLoad();
                            break;
                        case Hls.ErrorTypes.MEDIA_ERROR:
                            console.log("媒体错误,尝试恢复...");
                            hls.recoverMediaError();
                            break;
                        default:
                            console.log("无法恢复的错误,销毁 HLS 实例...");
                            hls.destroy();
                            break;
                    }
                }
            });
        } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
            // 如果浏览器原生支持 HLS(如 Safari),直接设置 video 的 src
            video.src = url;
            video.addEventListener('canplay', function () {
                video.play();
            });
        } else {
            // 如果浏览器不支持 HLS,提示用户
            console.log("您的浏览器不支持 HLS 视频播放。");
        }

        // 页面关闭时销毁 HLS 实例(避免资源泄漏)
        window.addEventListener('beforeunload', function () {
            if (hls) {
                hls.destroy();
            }
        });
    </script>
</body>
</html>
`
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprint(w, html)
}

前端实现倍速功能

package main

import (
	"fmt"
	"log"
	"net/http"
)

const (
	inputFile       = "./extended.mp4"
	outputDir       = "output"
	segmentDuration = "4" // 减小分片大小到 4 秒
	serverPort      = ":8999"
)

func main() {
	// 设置静态文件服务
	http.Handle("/output/", http.StripPrefix("/output/", http.FileServer(http.Dir(outputDir))))

	// 设置首页
	http.HandleFunc("/", serveIndex)

	fmt.Printf("服务器启动在 http://localhost%s\n", serverPort)
	log.Fatal(http.ListenAndServe(serverPort, nil))
}

func serveIndex(w http.ResponseWriter, r *http.Request) {
	html := `
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>HLS 视频播放</title>
    <!-- 引入 hls.js 库 -->
    <script type="text/javascript" src="https://cdn.jsdelivr.net/hls.js/latest/hls.min.js"></script>
</head>
<body>
    <!-- 视频播放容器 -->
    <video class="video" id="HLSPlayer" controls>
        <!-- 如果浏览器支持 HLS,这里会显示视频 -->
        <p>您的浏览器不支持 HLS 视频播放,请升级浏览器或使用支持 HLS 的设备。</p>
    </video>

    <!-- 倍速选择控件 -->
    <div style="margin-top: 10px;">
        <label for="speedControl">播放速度:</label>
        <select id="speedControl">
            <option value="0.5">0.5x</option>
            <option value="1.0" selected>1.0x</option>
            <option value="1.5">1.5x</option>
            <option value="2.0">2.0x</option>
        </select>
    </div>

    <script>
        // 获取视频播放器元素
        let video = document.getElementById("HLSPlayer");

        // HLS 视频流的 URL(请替换为你的 m3u8 文件路径)
        var url = '/output/playlist.m3u8';  // 替换为你的 HLS 流地址

        // 检查浏览器是否支持 HLS
        if (Hls.isSupported()) {
            // 创建 HLS 实例
            var hls = new Hls();
            hls.loadSource(url);  // 加载 HLS 流
            hls.attachMedia(video);  // 将 HLS 实例绑定到 video 元素
            hls.on(Hls.Events.MANIFEST_PARSED, function () {
                video.play();  // 当 HLS 流解析完成后自动播放
            });

            // 错误处理
            hls.on(Hls.Events.ERROR, function (event, data) {
                if (data.fatal) {
                    switch (data.type) {
                        case Hls.ErrorTypes.NETWORK_ERROR:
                            console.log("网络错误,尝试重新加载...");
                            hls.startLoad();
                            break;
                        case Hls.ErrorTypes.MEDIA_ERROR:
                            console.log("媒体错误,尝试恢复...");
                            hls.recoverMediaError();
                            break;
                        default:
                            console.log("无法恢复的错误,销毁 HLS 实例...");
                            hls.destroy();
                            break;
                    }
                }
            });
        } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
            // 如果浏览器原生支持 HLS(如 Safari),直接设置 video 的 src
            video.src = url;
            video.addEventListener('canplay', function () {
                video.play();
            });
        } else {
            // 如果浏览器不支持 HLS,提示用户
            console.log("您的浏览器不支持 HLS 视频播放。");
        }

        // 倍速控制
        document.getElementById("speedControl").addEventListener("change", function () {
            const selectedSpeed = parseFloat(this.value);
            video.playbackRate = selectedSpeed;
        });

        // 页面关闭时销毁 HLS 实例(避免资源泄漏)
        window.addEventListener('beforeunload', function () {
            if (hls) {
                hls.destroy();
            }
        });
    </script>
</body>
</html>
`
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprint(w, html)
}

加截图功能

package main

import (
	"fmt"
	"log"
	"net/http"
)

const (
	inputFile       = "./extended.mp4"
	outputDir       = "output"
	segmentDuration = "4" // 减小分片大小到 4 秒
	serverPort      = ":8999"
)

func main() {
	// 设置静态文件服务
	http.Handle("/output/", http.StripPrefix("/output/", http.FileServer(http.Dir(outputDir))))

	// 设置首页
	http.HandleFunc("/", serveIndex)

	fmt.Printf("服务器启动在 http://localhost%s\n", serverPort)
	log.Fatal(http.ListenAndServe(serverPort, nil))
}

func serveIndex(w http.ResponseWriter, r *http.Request) {
	html := `
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>HLS 视频播放与截图功能</title>
    <!-- 引入 hls.js 库 -->
    <script type="text/javascript" src="https://cdn.jsdelivr.net/hls.js/latest/hls.min.js"></script>
</head>
<body>
    <!-- 视频播放容器 -->
    <video class="video" id="HLSPlayer" controls>
        <p>您的浏览器不支持 HLS 视频播放,请升级浏览器或使用支持 HLS 的设备。</p>
    </video>

    <!-- 倍速选择控件 -->
    <div style="margin-top: 10px;">
        <label for="speedControl">播放速度:</label>
        <select id="speedControl">
            <option value="0.5">0.5x</option>
            <option value="1.0" selected>1.0x</option>
            <option value="1.5">1.5x</option>
            <option value="2.0">2.0x</option>
        </select>
    </div>

    <!-- 截图按钮 -->
    <button id="screenshotButton" style="margin-top: 10px;">截图并保存</button>

    <!-- 显示截图的区域 -->
    <div id="screenshotPreview" style="margin-top: 10px;">
        <h4>截图预览:</h4>
    </div>

    <script>
        // 获取视频播放器元素
        let video = document.getElementById("HLSPlayer");

        // HLS 视频流的 URL(请替换为你的 m3u8 文件路径)
        var url = '/output/playlist.m3u8';  // 替换为你的 HLS 流地址

        // 检查浏览器是否支持 HLS
        if (Hls.isSupported()) {
            // 创建 HLS 实例
            var hls = new Hls();
            hls.loadSource(url);  // 加载 HLS 流
            hls.attachMedia(video);  // 将 HLS 实例绑定到 video 元素
            hls.on(Hls.Events.MANIFEST_PARSED, function () {
                video.play();  // 当 HLS 流解析完成后自动播放
            });

            // 错误处理
            hls.on(Hls.Events.ERROR, function (event, data) {
                if (data.fatal) {
                    switch (data.type) {
                        case Hls.ErrorTypes.NETWORK_ERROR:
                            console.log("网络错误,尝试重新加载...");
                            hls.startLoad();
                            break;
                        case Hls.ErrorTypes.MEDIA_ERROR:
                            console.log("媒体错误,尝试恢复...");
                            hls.recoverMediaError();
                            break;
                        default:
                            console.log("无法恢复的错误,销毁 HLS 实例...");
                            hls.destroy();
                            break;
                    }
                }
            });
        } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
            // 如果浏览器原生支持 HLS(如 Safari),直接设置 video 的 src
            video.src = url;
            video.addEventListener('canplay', function () {
                video.play();
            });
        } else {
            // 如果浏览器不支持 HLS,提示用户
            console.log("您的浏览器不支持 HLS 视频播放。");
        }

        // 倍速控制
        document.getElementById("speedControl").addEventListener("change", function () {
            const selectedSpeed = parseFloat(this.value);
            video.playbackRate = selectedSpeed;
        });

        // 截图功能
        document.getElementById("screenshotButton").addEventListener("click", function () {
            // 创建一个 canvas 元素
            const canvas = document.createElement("canvas");
            canvas.width = video.videoWidth;
            canvas.height = video.videoHeight;
            const context = canvas.getContext("2d");

            // 绘制当前视频帧到 canvas
            context.drawImage(video, 0, 0, canvas.width, canvas.height);

            // 将 canvas 内容转换为图片(base64格式)
            const screenshot = canvas.toDataURL("image/png");

            // 显示截图
            const screenshotPreview = document.getElementById("screenshotPreview");
            screenshotPreview.innerHTML = '<img src="' + screenshot + '" alt="截图" style="max-width: 100%;">';

            // 创建下载链接并触发下载
            const downloadLink = document.createElement("a");
            downloadLink.href = screenshot;
            downloadLink.download = "screenshot.png"; // 设置下载文件名
            document.body.appendChild(downloadLink);
            downloadLink.click();
            document.body.removeChild(downloadLink);
        });

        // 页面关闭时销毁 HLS 实例(避免资源泄漏)
        window.addEventListener('beforeunload', function () {
            if (hls) {
                hls.destroy();
            }
        });
    </script>
</body>
</html>
`
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprint(w, html)
}

截图加水印

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"os/exec"
)

const (
	inputFile       = "./extended.mp4" // 输入的视频文件
	outputDir       = "output"         // 输出目录
	segmentDuration = "4"              // 分片时长
	serverPort      = ":8999"          // 服务器端口
)

func main() {
	// 确保输出目录存在
	if err := os.MkdirAll(outputDir, os.ModePerm); err != nil {
		log.Fatalf("创建输出目录失败: %v", err)
	}

	// 设置静态文件服务
	http.Handle("/output/", http.StripPrefix("/output/", http.FileServer(http.Dir(outputDir))))

	// 设置首页
	http.HandleFunc("/", serveIndex)

	// 设置截取视频片段的接口
	http.HandleFunc("/cut-video", cutVideoHandler)

	// 设置截图并添加水印的接口
	http.HandleFunc("/screenshot", screenshotHandler)

	fmt.Printf("服务器启动在 http://localhost%s\n", serverPort)
	log.Fatal(http.ListenAndServe(serverPort, nil))
}

func serveIndex(w http.ResponseWriter, r *http.Request) {
	html := `
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>HLS 视频播放与截图功能</title>
    <script type="text/javascript" src="https://cdn.jsdelivr.net/hls.js/latest/hls.min.js"></script>
</head>
<body>
    <video class="video" id="HLSPlayer" controls>
        <p>您的浏览器不支持 HLS 视频播放,请升级浏览器或使用支持 HLS 的设备。</p>
    </video>

    <div style="margin-top: 10px;">
        <label for="speedControl">播放速度:</label>
        <select id="speedControl">
            <option value="0.5">0.5x</option>
            <option value="1.0" selected>1.0x</option>
            <option value="1.5">1.5x</option>
            <option value="2.0">2.0x</option>
        </select>
    </div>

    <button id="screenshotButton" style="margin-top: 10px;">截图并保存</button>

    <button id="recordButton" style="margin-top: 10px;">开始录制</button>

    <div id="screenshotPreview" style="margin-top: 10px;">
        <h4>截图预览:</h4>
    </div>

    <script>
        let video = document.getElementById("HLSPlayer");
        const url = '/output/playlist.m3u8'; // 替换为你的 HLS 流地址
        let recording = false;
        let startTime = 0;
        let endTime = 0;

        if (Hls.isSupported()) {
            var hls = new Hls();
            hls.loadSource(url);
            hls.attachMedia(video);
            hls.on(Hls.Events.MANIFEST_PARSED, function () {
                video.play();
            });
        } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
            video.src = url;
            video.addEventListener('canplay', function () {
                video.play();
            });
        } else {
            console.log("您的浏览器不支持 HLS 视频播放。");
        }

        document.getElementById("speedControl").addEventListener("change", function () {
            video.playbackRate = parseFloat(this.value);
        });

        document.getElementById("screenshotButton").addEventListener("click", function () {
            const currentTime = video.currentTime;
            fetch('/screenshot?time=' + currentTime)
                .then(response => response.text())
                .then(data => {
                    alert(data);
                })
                .catch(error => {
                    console.error("截图失败:", error);
                    alert("截图失败,请检查控制台日志。");
                });
        });

        document.getElementById("recordButton").addEventListener("click", function () {
            if (!recording) {
                startTime = video.currentTime;
                recording = true;
                this.textContent = "结束录制";
            } else {
                endTime = video.currentTime;
                recording = false;
                this.textContent = "开始录制";

                fetch('/cut-video?start=' + startTime + '&end=' + endTime)
                    .then(response => response.text())
                    .then(data => {
                        alert(data);
                    })
                    .catch(error => {
                        console.error("截取视频失败:", error);
                        alert("截取视频失败,请检查控制台日志。");
                    });
            }
        });
    </script>
</body>
</html>
`
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprint(w, html)
}

func cutVideoHandler(w http.ResponseWriter, r *http.Request) {
	start := r.URL.Query().Get("start")
	end := r.URL.Query().Get("end")

	if start == "" || end == "" {
		http.Error(w, "缺少开始或结束时间参数", http.StatusBadRequest)
		return
	}

	outputFile := fmt.Sprintf("%s/clip_%s_to_%s.mp4", outputDir, start, end)
	cmd := exec.Command("ffmpeg", "-i", inputFile, "-ss", start, "-to", end, "-c", "copy", outputFile)
	err := cmd.Run()
	if err != nil {
		http.Error(w, fmt.Sprintf("截取视频失败: %v", err), http.StatusInternalServerError)
		return
	}

	w.Write([]byte(fmt.Sprintf("视频片段已成功截取并保存到 %s", outputFile)))
}

func screenshotHandler(w http.ResponseWriter, r *http.Request) {
	time := r.URL.Query().Get("time")

	if time == "" {
		http.Error(w, "缺少时间参数", http.StatusBadRequest)
		return
	}

	// 截图并添加水印
	outputFile := fmt.Sprintf("%s/screenshot_%s.png", outputDir, time)
	cmd := exec.Command("ffmpeg", "-i", inputFile, "-ss", time, "-vframes", "1", "-vf", "drawtext=text='Watermark':x=10:y=10:fontsize=24:fontcolor=white", outputFile)
	err := cmd.Run()
	if err != nil {
		http.Error(w, fmt.Sprintf("截图失败: %v", err), http.StatusInternalServerError)
		return
	}

	w.Write([]byte(fmt.Sprintf("截图已成功保存到 %s", outputFile)))
}

截取录制视频

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"os/exec"
)

const (
	inputFile       = "./extended.mp4" // 输入的视频文件
	outputDir       = "output"         // 输出目录
	segmentDuration = "4"              // 分片时长
	serverPort      = ":8999"          // 服务器端口
)

func main() {
	// 确保输出目录存在
	if err := os.MkdirAll(outputDir, os.ModePerm); err != nil {
		log.Fatalf("创建输出目录失败: %v", err)
	}

	// 设置静态文件服务
	http.Handle("/output/", http.StripPrefix("/output/", http.FileServer(http.Dir(outputDir))))

	// 设置首页
	http.HandleFunc("/", serveIndex)

	// 设置截取视频片段的接口
	http.HandleFunc("/cut-video", cutVideoHandler)

	fmt.Printf("服务器启动在 http://localhost%s\n", serverPort)
	log.Fatal(http.ListenAndServe(serverPort, nil))
}

func serveIndex(w http.ResponseWriter, r *http.Request) {
	html := `
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>HLS 视频播放与截图功能</title>
    <script type="text/javascript" src="https://cdn.jsdelivr.net/hls.js/latest/hls.min.js"></script>
</head>
<body>
    <video class="video" id="HLSPlayer" controls>
        <p>您的浏览器不支持 HLS 视频播放,请升级浏览器或使用支持 HLS 的设备。</p>
    </video>

    <div style="margin-top: 10px;">
        <label for="speedControl">播放速度:</label>
        <select id="speedControl">
            <option value="0.5">0.5x</option>
            <option value="1.0" selected>1.0x</option>
            <option value="1.5">1.5x</option>
            <option value="2.0">2.0x</option>
        </select>
    </div>

    <button id="screenshotButton" style="margin-top: 10px;">截图并保存</button>

    <div style="margin-top: 10px;">
        <label for="startRange">开始时间(秒):</label>
        <input type="number" id="startRange" min="0" value="0">
        <label for="endRange">结束时间(秒):</label>
        <input type="number" id="endRange" min="0" value="10">
        <button id="cutVideoButton">截取视频片段</button>
    </div>

    <div id="screenshotPreview" style="margin-top: 10px;">
        <h4>截图预览:</h4>
    </div>

    <script>
        let video = document.getElementById("HLSPlayer");
        const url = '/output/playlist.m3u8'; // 替换为你的 HLS 流地址

        if (Hls.isSupported()) {
            var hls = new Hls();
            hls.loadSource(url);
            hls.attachMedia(video);
            hls.on(Hls.Events.MANIFEST_PARSED, function () {
                video.play();
            });
        } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
            video.src = url;
            video.addEventListener('canplay', function () {
                video.play();
            });
        } else {
            console.log("您的浏览器不支持 HLS 视频播放。");
        }

        document.getElementById("speedControl").addEventListener("change", function () {
            video.playbackRate = parseFloat(this.value);
        });

        document.getElementById("screenshotButton").addEventListener("click", function () {
            const canvas = document.createElement("canvas");
            canvas.width = video.videoWidth;
            canvas.height = video.videoHeight;
            const context = canvas.getContext("2d");
            context.drawImage(video, 0, 0, canvas.width, canvas.height);
            const screenshot = canvas.toDataURL("image/png");
            const screenshotPreview = document.getElementById("screenshotPreview");
            screenshotPreview.innerHTML = '<img src="' + screenshot + '" alt="截图" style="max-width: 100%;">';
            const downloadLink = document.createElement("a");
            downloadLink.href = screenshot;
            downloadLink.download = "screenshot.png";
            document.body.appendChild(downloadLink);
            downloadLink.click();
            document.body.removeChild(downloadLink);
        });

        document.getElementById("cutVideoButton").addEventListener("click", function () {
            const start = parseFloat(document.getElementById("startRange").value);
            const end = parseFloat(document.getElementById("endRange").value);

            if (isNaN(start) || isNaN(end) || start >= end) {
                alert("请输入有效的时间范围!");
                return;
            }

            fetch(` + "`" + `/cut-video?start=${start}&end=${end}` + "`" + `)
                .then(response => response.text())
                .then(data => {
                    alert(data);
                })
                .catch(error => {
                    console.error("截取视频失败:", error);
                    alert("截取视频失败,请检查控制台日志。");
                });
        });

    </script>
</body>
</html>
`
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprint(w, html)
}

func cutVideoHandler(w http.ResponseWriter, r *http.Request) {
	start := r.URL.Query().Get("start")
	end := r.URL.Query().Get("end")

	if start == "" || end == "" {
		http.Error(w, "缺少开始或结束时间参数", http.StatusBadRequest)
		return
	}

	outputFile := fmt.Sprintf("%s/clip_%s_to_%s.mp4", outputDir, start, end)
	cmd := exec.Command("ffmpeg", "-i", inputFile, "-ss", start, "-to", end, "-c", "copy", outputFile)
	err := cmd.Run()
	if err != nil {
		http.Error(w, fmt.Sprintf("截取视频失败: %v", err), http.StatusInternalServerError)
		return
	}

	w.Write([]byte(fmt.Sprintf("视频片段已成功截取并保存到 %s", outputFile)))
}

视频加水印

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"os/exec"
)

const (
	inputFile       = "./extended.mp4" // 输入的视频文件
	outputDir       = "output"         // 输出目录
	segmentDuration = "4"              // 分片时长
	serverPort      = ":8999"          // 服务器端口
	watermarkText   = "Watermark"      // 水印文本
)

func main() {
	// 确保输出目录存在
	if err := os.MkdirAll(outputDir, os.ModePerm); err != nil {
		log.Fatalf("创建输出目录失败: %v", err)
	}

	// 设置静态文件服务
	http.Handle("/output/", http.StripPrefix("/output/", http.FileServer(http.Dir(outputDir))))

	// 设置首页
	http.HandleFunc("/", serveIndex)

	// 设置截取视频片段的接口
	http.HandleFunc("/cut-video", cutVideoHandler)

	// 设置截图并添加水印的接口
	http.HandleFunc("/screenshot", screenshotHandler)

	// 设置下载列表页面
	http.HandleFunc("/downloads", downloadsHandler)

	fmt.Printf("服务器启动在 http://localhost%s\n", serverPort)
	log.Fatal(http.ListenAndServe(serverPort, nil))
}

func serveIndex(w http.ResponseWriter, r *http.Request) {
	html := `
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>HLS 视频播放与截图功能</title>
    <script type="text/javascript" src="https://cdn.jsdelivr.net/hls.js/latest/hls.min.js"></script>
</head>
<body>
    <video class="video" id="HLSPlayer" controls>
        <p>您的浏览器不支持 HLS 视频播放,请升级浏览器或使用支持 HLS 的设备。</p>
    </video>

    <div style="margin-top: 10px;">
        <label for="speedControl">播放速度:</label>
        <select id="speedControl">
            <option value="0.5">0.5x</option>
            <option value="1.0" selected>1.0x</option>
            <option value="1.5">1.5x</option>
            <option value="2.0">2.0x</option>
        </select>
    </div>

    <button id="screenshotButton" style="margin-top: 10px;">截图并保存</button>

    <button id="recordButton" style="margin-top: 10px;">开始录制</button>

    <div id="screenshotPreview" style="margin-top: 10px;">
        <h4>截图预览:</h4>
    </div>

    <script>
        let video = document.getElementById("HLSPlayer");
        const url = '/output/playlist.m3u8'; // 替换为你的 HLS 流地址
        let recording = false;
        let startTime = 0;
        let endTime = 0;

        if (Hls.isSupported()) {
            var hls = new Hls();
            hls.loadSource(url);
            hls.attachMedia(video);
            hls.on(Hls.Events.MANIFEST_PARSED, function () {
                video.play();
            });
        } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
            video.src = url;
            video.addEventListener('canplay', function () {
                video.play();
            });
        } else {
            console.log("您的浏览器不支持 HLS 视频播放。");
        }

        document.getElementById("speedControl").addEventListener("change", function () {
            video.playbackRate = parseFloat(this.value);
        });

        document.getElementById("screenshotButton").addEventListener("click", function () {
            const currentTime = video.currentTime;
            fetch('/screenshot?time=' + currentTime)
                .then(response => response.text())
                .then(data => {
                    alert(data);
                })
                .catch(error => {
                    console.error("截图失败:", error);
                    alert("截图失败,请检查控制台日志。");
                });
        });

        document.getElementById("recordButton").addEventListener("click", function () {
            if (!recording) {
                startTime = video.currentTime;
                recording = true;
                this.textContent = "结束录制";
            } else {
                endTime = video.currentTime;
                recording = false;
                this.textContent = "开始录制";

                fetch('/cut-video?start=' + startTime + '&end=' + endTime)
                    .then(response => response.text())
                    .then(data => {
                        alert(data);
                    })
                    .catch(error => {
                        console.error("截取视频失败:", error);
                        alert("截取视频失败,请检查控制台日志。");
                    });
            }
        });
    </script>
</body>
</html>
`
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprint(w, html)
}

func cutVideoHandler(w http.ResponseWriter, r *http.Request) {
	start := r.URL.Query().Get("start")
	end := r.URL.Query().Get("end")

	if start == "" || end == "" {
		http.Error(w, "缺少开始或结束时间参数", http.StatusBadRequest)
		return
	}

	// 生成带水印的视频文件名
	outputFile := fmt.Sprintf("%s/clip_%s_to_%s.mp4", outputDir, start, end)
	tempFile := fmt.Sprintf("%s/temp_clip_%s_to_%s.mp4", outputDir, start, end)

	// 第一步:截取视频片段
	cmd1 := exec.Command("ffmpeg", "-i", inputFile, "-ss", start, "-to", end, "-c", "copy", tempFile)
	err := cmd1.Run()
	if err != nil {
		http.Error(w, fmt.Sprintf("截取视频失败: %v", err), http.StatusInternalServerError)
		return
	}

	// 第二步:给视频片段添加水印
	cmd2 := exec.Command("ffmpeg", "-i", tempFile, "-vf", fmt.Sprintf("drawtext=text='%s':x=10:y=10:fontsize=24:fontcolor=white", watermarkText), "-c:a", "copy", outputFile)
	err = cmd2.Run()
	if err != nil {
		http.Error(w, fmt.Sprintf("添加水印失败: %v", err), http.StatusInternalServerError)
		return
	}

	// 删除临时文件
	os.Remove(tempFile)

	w.Write([]byte(fmt.Sprintf("视频片段已成功截取并添加水印,保存到 %s", outputFile)))
}

func screenshotHandler(w http.ResponseWriter, r *http.Request) {
	time := r.URL.Query().Get("time")

	if time == "" {
		http.Error(w, "缺少时间参数", http.StatusBadRequest)
		return
	}

	outputFile := fmt.Sprintf("%s/screenshot_%s.png", outputDir, time)
	cmd := exec.Command("ffmpeg", "-i", inputFile, "-ss", time, "-vframes", "1", "-vf", fmt.Sprintf("drawtext=text='%s':x=10:y=10:fontsize=24:fontcolor=white", watermarkText), outputFile)
	err := cmd.Run()
	if err != nil {
		http.Error(w, fmt.Sprintf("截图失败: %v", err), http.StatusInternalServerError)
		return
	}

	w.Write([]byte(fmt.Sprintf("截图已成功保存到 %s", outputFile)))
}

func downloadsHandler(w http.ResponseWriter, r *http.Request) {
	files, err := os.ReadDir(outputDir)
	if err != nil {
		http.Error(w, "无法读取下载目录", http.StatusInternalServerError)
		return
	}

	html := `<html><body><h1>下载列表</h1><ul>`
	for _, file := range files {
		fileName := file.Name()
		// filePath := filepath.Join(outputDir, fileName)
		html += fmt.Sprintf(`<li><a href="/output/%s" download>%s</a></li>`, fileName, fileName)
	}
	html += `</ul></body></html>`

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprint(w, html)
}

开始录制结束录制控件

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"os/exec"
)

const (
	inputFile       = "./extended.mp4" // 输入的视频文件
	outputDir       = "output"         // 输出目录
	segmentDuration = "4"              // 分片时长
	serverPort      = ":8999"          // 服务器端口
)

func main() {
	// 确保输出目录存在
	if err := os.MkdirAll(outputDir, os.ModePerm); err != nil {
		log.Fatalf("创建输出目录失败: %v", err)
	}

	// 设置静态文件服务
	http.Handle("/output/", http.StripPrefix("/output/", http.FileServer(http.Dir(outputDir))))

	// 设置首页
	http.HandleFunc("/", serveIndex)

	// 设置截取视频片段的接口
	http.HandleFunc("/cut-video", cutVideoHandler)

	fmt.Printf("服务器启动在 http://localhost%s\n", serverPort)
	log.Fatal(http.ListenAndServe(serverPort, nil))
}

func serveIndex(w http.ResponseWriter, r *http.Request) {
	html := `
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>HLS 视频播放与截图功能</title>
    <script type="text/javascript" src="https://cdn.jsdelivr.net/hls.js/latest/hls.min.js"></script>
</head>
<body>
    <video class="video" id="HLSPlayer" controls>
        <p>您的浏览器不支持 HLS 视频播放,请升级浏览器或使用支持 HLS 的设备。</p>
    </video>

    <div style="margin-top: 10px;">
        <label for="speedControl">播放速度:</label>
        <select id="speedControl">
            <option value="0.5">0.5x</option>
            <option value="1.0" selected>1.0x</option>
            <option value="1.5">1.5x</option>
            <option value="2.0">2.0x</option>
        </select>
    </div>

    <button id="screenshotButton" style="margin-top: 10px;">截图并保存</button>

    <button id="recordButton" style="margin-top: 10px;">开始录制</button>

    <div id="screenshotPreview" style="margin-top: 10px;">
        <h4>截图预览:</h4>
    </div>

    <script>
        let video = document.getElementById("HLSPlayer");
        const url = '/output/playlist.m3u8'; // 替换为你的 HLS 流地址
        let recording = false;
        let startTime = 0;
        let endTime = 0;

        if (Hls.isSupported()) {
            var hls = new Hls();
            hls.loadSource(url);
            hls.attachMedia(video);
            hls.on(Hls.Events.MANIFEST_PARSED, function () {
                video.play();
            });
        } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
            video.src = url;
            video.addEventListener('canplay', function () {
                video.play();
            });
        } else {
            console.log("您的浏览器不支持 HLS 视频播放。");
        }

        document.getElementById("speedControl").addEventListener("change", function () {
            video.playbackRate = parseFloat(this.value);
        });

        document.getElementById("screenshotButton").addEventListener("click", function () {
            const canvas = document.createElement("canvas");
            canvas.width = video.videoWidth;
            canvas.height = video.videoHeight;
            const context = canvas.getContext("2d");
            context.drawImage(video, 0, 0, canvas.width, canvas.height);
            const screenshot = canvas.toDataURL("image/png");
            const screenshotPreview = document.getElementById("screenshotPreview");
            screenshotPreview.innerHTML = '<img src="' + screenshot + '" alt="截图" style="max-width: 100%;">';
            const downloadLink = document.createElement("a");
            downloadLink.href = screenshot;
            downloadLink.download = "screenshot.png";
            document.body.appendChild(downloadLink);
            downloadLink.click();
            document.body.removeChild(downloadLink);
        });

 document.getElementById("recordButton").addEventListener("click", function () {
            if (!recording) {
                // 开始录制
                startTime = video.currentTime;
                recording = true;
                this.textContent = "结束录制";
            } else {
                // 结束录制
                endTime = video.currentTime;
                recording = false;
                this.textContent = "开始录制";

                // 调用后端接口截取视频片段
                fetch(` + "`" + `/cut-video?start=${startTime}&end=${endTime}` + "`" + `)
                    .then(response => response.text())
                    .then(data => {
                        alert(data);
                    })
                    .catch(error => {
                        console.error("截取视频失败:", error);
                        alert("截取视频失败,请检查控制台日志。");
                    });
            }
        });
    </script>
</body>
</html>
`
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprint(w, html)
}

func cutVideoHandler(w http.ResponseWriter, r *http.Request) {
	start := r.URL.Query().Get("start")
	end := r.URL.Query().Get("end")

	if start == "" || end == "" {
		http.Error(w, "缺少开始或结束时间参数", http.StatusBadRequest)
		return
	}

	outputFile := fmt.Sprintf("%s/clip_%s_to_%s.mp4", outputDir, start, end)
	cmd := exec.Command("ffmpeg", "-i", inputFile, "-ss", start, "-to", end, "-c", "copy", outputFile)
	err := cmd.Run()
	if err != nil {
		http.Error(w, fmt.Sprintf("截取视频失败: %v", err), http.StatusInternalServerError)
		return
	}

	w.Write([]byte(fmt.Sprintf("视频片段已成功截取并保存到 %s", outputFile)))
}

结合富文本编辑器,实现边看视频变做笔记

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
)

const (
	inputFile       = "./extended.mp4" // 输入的视频文件
	outputDir       = "output"         // 输出目录
	segmentDuration = "4"              // 分片时长
	serverPort      = ":8999"          // 服务器端口
	contentFile     = "content.json"   // 保存笔记的文件
)

func main() {
	// 确保输出目录存在
	if err := os.MkdirAll(outputDir, os.ModePerm); err != nil {
		log.Fatalf("创建输出目录失败: %v", err)
	}

	// 设置静态文件服务
	http.Handle("/output/", http.StripPrefix("/output/", http.FileServer(http.Dir(outputDir))))

	// 设置首页
	http.HandleFunc("/", serveIndex)

	// 设置截取视频片段的接口
	http.HandleFunc("/cut-video", cutVideoHandler)

	// 设置保存笔记的接口
	http.HandleFunc("/save", handleSave)

	// 设置加载笔记的接口
	http.HandleFunc("/load", handleLoad)

	fmt.Printf("服务器启动在 http://localhost%s\n", serverPort)
	log.Fatal(http.ListenAndServe(serverPort, nil))
}

func serveIndex(w http.ResponseWriter, r *http.Request) {
	html := `
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>视频播放与笔记功能</title>
    <script src="https://cdn.tiny.cloud/1/你的key/tinymce/6/tinymce.min.js" referrerpolicy="origin"></script>
	<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
</head>
<body>
    <h1>视频播放与笔记功能</h1>
    <video class="video" id="HLSPlayer" controls>
        <p>您的浏览器不支持 HLS 视频播放,请升级浏览器或使用支持 HLS 的设备。</p>
    </video>
    <div style="margin-top: 10px;">
        <label for="speedControl">播放速度:</label>
        <select id="speedControl">
            <option value="0.5">0.5x</option>
            <option value="1.0" selected>1.0x</option>
            <option value="1.5">1.5x</option>
            <option value="2.0">2.0x</option>
        </select>
    </div>
    <button id="screenshotButton" style="margin-top: 10px;">截图并保存</button>
    <button id="recordButton" style="margin-top: 10px;">开始录制</button>
    <div id="screenshotPreview" style="margin-top: 10px;">
        <h4>截图预览:</h4>
    </div>
    <textarea id="editor">在这里记录笔记...</textarea>
    <br>
    <button onclick="saveContent()">保存笔记</button>
    <button onclick="loadContent()">加载笔记</button>
    <script>
        let video = document.getElementById("HLSPlayer");
        const url = '/output/playlist.m3u8'; // 替换为你的 HLS 流地址
        let recording = false;
        let startTime = 0;
        let endTime = 0;

        if (Hls.isSupported()) {
            var hls = new Hls();
            hls.loadSource(url);
            hls.attachMedia(video);
            hls.on(Hls.Events.MANIFEST_PARSED, function () {
                video.play();
            });
        } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
            video.src = url;
            video.addEventListener('canplay', function () {
                video.play();
            });
        } else {
            console.log("您的浏览器不支持 HLS 视频播放。");
        }

        document.getElementById("speedControl").addEventListener("change", function () {
            video.playbackRate = parseFloat(this.value);
        });

        document.getElementById("screenshotButton").addEventListener("click", function () {
            const canvas = document.createElement("canvas");
            canvas.width = video.videoWidth;
            canvas.height = video.videoHeight;
            const context = canvas.getContext("2d");
            context.drawImage(video, 0, 0, canvas.width, canvas.height);
            const screenshot = canvas.toDataURL("image/png");
            const screenshotPreview = document.getElementById("screenshotPreview");
            screenshotPreview.innerHTML = '<img src="' + screenshot + '" alt="截图" style="max-width: 100%;">';

            // 将截图插入到编辑器中
            const editor = tinymce.get('editor');
            editor.insertContent('<img src="' + screenshot + '" alt="截图">');
        });

        
        document.getElementById("recordButton").addEventListener("click", function () {
            if (!recording) {
                startTime = video.currentTime;
                recording = true;
                this.textContent = "结束录制";
            } else {
                endTime = video.currentTime;
                recording = false;
                this.textContent = "开始录制";

                fetch('/cut-video?start=' + startTime + '&end=' + endTime)
                    .then(response => response.text())
                    .then(data => {
                        alert(data);
                    })
                    .catch(error => {
                        console.error("截取视频失败:", error);
                        alert("截取视频失败,请检查控制台日志。");
                    });
            }
        });

        tinymce.init({
            selector: '#editor',
            plugins: 'anchor autolink charmap codesample emoticons image link lists media searchreplace table visualblocks wordcount',
            toolbar: 'undo redo | blocks fontfamily fontsize | bold italic underline strikethrough | link image media table | align lineheight | numlist bullist indent outdent | emoticons charmap | removeformat',
        });

        function saveContent() {
            const content = tinymce.get('editor').getContent();
            fetch('/save', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({ text: content }),
            })
            .then(response => {
                if (response.ok) {
                    alert('笔记保存成功!');
                } else {
                    alert('保存笔记失败。');
                }
            });
        }

        function loadContent() {
            fetch('/load')
            .then(response => {
                if (!response.ok) {
                    throw new Error('加载失败');
                }
                return response.json();
            })
            .then(data => {
                tinymce.get('editor').setContent(data.text);
                console.log('笔记加载成功');
            })
            .catch(error => {
                console.error('加载笔记失败:', error);
                alert('加载笔记失败: ' + error.message);
            });
        }
    </script>
</body>
</html>
`
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	fmt.Fprint(w, html)
}

func cutVideoHandler(w http.ResponseWriter, r *http.Request) {
	start := r.URL.Query().Get("start")
	end := r.URL.Query().Get("end")

	if start == "" || end == "" {
		http.Error(w, "缺少开始或结束时间参数", http.StatusBadRequest)
		return
	}

	outputFile := fmt.Sprintf("%s/clip_%s_to_%s.mp4", outputDir, start, end)
	cmd := exec.Command("ffmpeg", "-i", inputFile, "-ss", start, "-to", end, "-c", "copy", outputFile)
	err := cmd.Run()
	if err != nil {
		http.Error(w, fmt.Sprintf("截取视频失败: %v", err), http.StatusInternalServerError)
		return
	}

	w.Write([]byte(fmt.Sprintf("视频片段已成功截取并保存到 %s", outputFile)))
}

// Content 结构体用于保存和加载笔记内容
type Content struct {
	Text string `json:"text"`
}

// handleSave 处理保存笔记的请求
func handleSave(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	var content Content
	err := json.NewDecoder(r.Body).Decode(&content)
	if err != nil {
		http.Error(w, "Invalid request body: "+err.Error(), http.StatusBadRequest)
		return
	}

	err = ioutil.WriteFile(contentFile, []byte(content.Text), 0644)
	if err != nil {
		http.Error(w, "Failed to save content: "+err.Error(), http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusOK)
	w.Write([]byte("Content saved successfully"))
}

// handleLoad 处理加载笔记的请求
func handleLoad(w http.ResponseWriter, r *http.Request) {
	if _, err := os.Stat(contentFile); os.IsNotExist(err) {
		http.Error(w, "No saved content found", http.StatusNotFound)
		return
	}

	data, err := ioutil.ReadFile(contentFile)
	if err != nil {
		http.Error(w, "Failed to read content: "+err.Error(), http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(Content{Text: string(data)})
}

ceph存储视频,文本文件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值