diff --git a/.gitignore b/.gitignore index 192432e..cf82266 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ *.avi /archived_writer/ /tester/ +/reader/html/ diff --git a/reader/cmd/main.go b/reader/cmd/main.go new file mode 100644 index 0000000..ec34160 --- /dev/null +++ b/reader/cmd/main.go @@ -0,0 +1,30 @@ +package main + +import ( + "fmt" + "log" + "net/http" + "reader/pkg/handlers" +) + +func main() { + path := "/home/psa/GoRepository/" + port := 8080 + + http.HandleFunc("GET /download", handlers.Download) // example request: {"date": "07-03-2025", "start_time": "16-43", "end_time": "16-44"} + http.HandleFunc("GET /hls", handlers.HLS) + //http.Handle("/", addHeaders(http.FileServer(http.Dir(path)))) + + log.Println("Starting server on:") + log.Printf("Serving %s on HTTP port: %d\n", path, port) + + log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", port), nil)) + +} + +//func addHeaders(h http.Handler) http.Handler { +// return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { +// w.Header().Set("Access-Control-Allow-Origin", "*") +// h.ServeHTTP(w, r) +// }) +//} diff --git a/reader/go.mod b/reader/go.mod new file mode 100644 index 0000000..a799cc8 --- /dev/null +++ b/reader/go.mod @@ -0,0 +1,5 @@ +module reader + +go 1.23.6 + +require git.insit.tech/sas/rtsp_proxy v0.0.0-20250310124520-82fa76149f4e // indirect diff --git a/reader/go.sum b/reader/go.sum new file mode 100644 index 0000000..b4d241c --- /dev/null +++ b/reader/go.sum @@ -0,0 +1,2 @@ +git.insit.tech/sas/rtsp_proxy v0.0.0-20250310124520-82fa76149f4e h1:JeOZvcZA4JHfoBG5ES9tpSHrhOj1jmjFzSJAyKIjApU= +git.insit.tech/sas/rtsp_proxy v0.0.0-20250310124520-82fa76149f4e/go.mod h1:9Yw6g7jcG9fIkWh6FGXSWTyZs4d7EQWaRhdKnnH2TvA= diff --git a/reader/internal/processor/file.go b/reader/internal/processor/file.go new file mode 100644 index 0000000..0bc4a4e --- /dev/null +++ b/reader/internal/processor/file.go @@ -0,0 +1,238 @@ +package processor + +import ( + "fmt" + "os" + "os/exec" + "strconv" + "strings" + "time" +) + +// partitionTime convert numbers from type STRING to type INT. +func partitionTime(time string) (startHour int, startMinute int, err error) { + // Part hours and minutes. + s := []byte(time) + h := []byte{s[0], s[1]} + m := []byte{s[3], s[4]} + + // Transforms hours and minutes into INTs. + startHour, err = strconv.Atoi(string(h)) + if err != nil { + return 0, 0, err + } + startMinute, err = strconv.Atoi(string(m)) + if err != nil { + return 0, 0, err + } + + return startHour, startMinute, nil +} + +// createTXT collects filenames into TXT file. +func createTXT(path, date, startTime, endTime string) (string, error) { + //fileNames := make([]string, 0) + + fileNameTXT := startTime + "_" + endTime + ".txt" + f, err := os.Create(path + fileNameTXT) + if err != nil { + return "", fmt.Errorf("create file error: %s", err.Error()) + } + defer f.Close() + + // Read the directory. + dirEntry, err := os.ReadDir(path) + if err != nil { + return "", fmt.Errorf("read directory error: %s", err.Error()) + } + + // Calculate start time and end time of the required fragment. + startHour, startMinute, endHour, endMinute := calcNeededTime(startTime, endTime) + + for i := startHour; i <= endHour; i++ { + for j := startMinute; j < endMinute; j++ { // exclude the last minute as endMinute is the final time + for _, entry := range dirEntry { + if strings.Contains(entry.Name(), strconv.Itoa(i)+"-"+strconv.Itoa(j)+"-00"+"_"+date) { + _, err = f.WriteString("file '" + entry.Name() + "'\n") + if err != nil { + return "", fmt.Errorf("write file error: %s", err.Error()) + } + } + } + } + } + + return fileNameTXT, nil +} + +// mergeFiles merges the collected files into one MP4 file. +func mergeFiles(path, fileNamesTXT string) (string, error) { + fileNameRes := time.Now().Format("15-04-05") + "_video.mp4" + + cmd := exec.Command("ffmpeg", + "-f", "concat", + "-safe", "0", + "-fflags", "+genpts", + "-i", path+fileNamesTXT, + "-c", "copy", + path+fileNameRes) + + err := cmd.Run() + if err != nil { + return "", fmt.Errorf("merge files error: %s", err.Error()) + } + + return fileNameRes, nil +} + +///////////////////////////////////////////////////////////////////////////////////// + +//// Функция copyFile находит файл в репозитории и создает его копию. +//func copyFiles(path string, filename []string) (filenameCopied []string, err error) { +// for i := 0; i < len(filename); i++ { +// input, err := os.Open(path + filename[i]) +// if err != nil { +// log.Println("Ошибка открытия input файла: ", err) +// } +// defer func() { +// err = input.Close() +// if err != nil { +// log.Println("Ошибка закрытия input файла.") +// } +// }() +// +// output, err := os.Create(time.Now().Format("15-04-05") + "video.mkv") +// if err != nil { +// log.Println("Ошибка создания output файла: ", err) +// } +// defer func() { +// err = output.Close() +// if err != nil { +// log.Println("Ошибка закрытия output файла.") +// } +// +// }() +// +// _, err = io.Copy(output, input) +// if err != nil { +// log.Println("Ошибка копирования файла") +// } +// } +// +// log.Println("Файлы скопированы.") +// return filename, err +//} +// +//// MergeMKV принимает названия видеофайлов для объединения. +//func MergeMKV(filenames ...string) { +// // Создание файла со списком видеофайлов для объединения +// f, err := os.Create("videoList.txt") +// if err != nil { +// log.Fatalln("Ошибка создания файла со списком видеофайлов для объединения", err) +// } +// defer func() { +// err = f.Close() +// if err != nil { +// log.Fatalln("Ошибка закрытия файла: ", err.Error()) +// } +// }() +// +// // Запись видеофайлов для объединения +// n := len(filenames) +// +// for i := 0; i < n; i++ { +// _, err = f.WriteString("file '" + filenames[i] + "'\n") +// if err != nil { +// log.Fatalln(err) +// } +// } +// +// err = mergeFfmpeg(f) +// if err != nil { +// log.Fatalln("Ошибка объединения видеофайлов с помощью ffmpeg: ", err) +// } +// +// err = os.Remove("videoList.txt") +// if err != nil { +// log.Println("Ошибка удаления временного файла videoList.txt: ", err) +// } +// log.Println("Временный файл videoList.txt успешно удален") +//} +// +//// DeleteTrimmedFragments удаляет временно созданные файлы. +//func DeleteTrimmedFragments(filenames ...string) { +// n := len(filenames) +// +// for i := 0; i < n; i++ { +// err := os.Remove(filenames[i]) +// if err != nil { +// log.Printf("Ошибка удаления временного файла %s: %s", filenames[i], err.Error()) +// } +// log.Printf("Временный файл %s успешно удален", filenames[i]) +// } +//} +// +// +//// createFilename forms first part of the filename which contains time and date. +//func createFilename(time, date string) (fileName string) { +// s := []byte(time) +// s[3], s[4] = '0', '0' +// fileName = string(s) + "_" + date +// return fileName +//} +// +//// Добавление одного часа к строке в формате ЧЧ-ММ +//func addHour(startTime string) (fileName string) { +// s := []byte(startTime) +// if s[0] == '0' && s[1] == '9' { +// s[0] = '1' +// s[1] = '0' +// } else if s[0] == '1' && s[1] == '9' { +// s[0] = '2' +// s[1] = '0' +// } else { +// s[1]++ +// } +// fileName = string(s) +// return fileName +//} +// +//// Проверка наличия файла +//func checkFile(path, fileName string) (string, error) { +// found := false +// filenameIn := fileName +// +// dirEntry, err := os.ReadDir(path) +// if err != nil { +// return "", err +// } +// for _, entry := range dirEntry { +// if strings.Contains(entry.Name(), filenameIn) { +// filenameIn = entry.Name() +// break +// } +// return "", fmt.Errorf("file %s not found", filenameIn) +// } +// +// err = filepath.Walk(path, func(filePath string, info os.FileInfo, err error) error { +// if err != nil { +// return err // Возвращаем ошибку, если возникла +// } +// if !info.IsDir() && info.Name() == filenameIn { +// log.Println("Файл обнаружен:", filePath) +// found = true +// return filepath.SkipDir // Останавливаем обход после нахождения +// } +// return nil +// }) +// +// if err != nil { +// return "", err +// } +// +// if !found { +// return "", errors.New("file not found") +// } +// +// return filenameIn, nil +//} diff --git a/reader/internal/processor/proc.go b/reader/internal/processor/proc.go new file mode 100644 index 0000000..7bc99dc --- /dev/null +++ b/reader/internal/processor/proc.go @@ -0,0 +1,26 @@ +package processor + +import ( + "fmt" +) + +func Process(date, startTime, endTime string) (string, error) { + // Set path with the records. + path := "/home/psa/GoRepository/data/1280x720/" + + // Collect filenames into TXT file. + fileNamesTXT, err := createTXT(path, date, startTime, endTime) + if err != nil { + return "", fmt.Errorf("collect filenames into TXT file error: %s", err.Error()) + } + + // Merge the collected files into one MP4 file. + fileNameRes, err := mergeFiles(path, fileNamesTXT) + if err != nil { + return "", fmt.Errorf("merge files error: %s", err.Error()) + } + + pathFileNameRes := path + fileNameRes + + return pathFileNameRes, nil +} diff --git a/reader/internal/processor/time.go b/reader/internal/processor/time.go new file mode 100644 index 0000000..a486594 --- /dev/null +++ b/reader/internal/processor/time.go @@ -0,0 +1,47 @@ +package processor + +import "log" + +// calcNeededTime accepts the start and the end of the recording time, converts the time from the format STRING to the +// format INT and returns the hour and the minute of the start recording time, the hour and the minute of the end +// recording time. +func calcNeededTime(startTime, endTime string) (startHour, startMinute, endHour, endMinute int) { + // Calc needed time. + startHour, startMinute, err := partitionTime(startTime) + if err != nil { + log.Fatal("Ошибка конвертации: ", err) + } + endHour, endMinute, err = partitionTime(endTime) + if err != nil { + log.Fatal("Ошибка конвертации: ", err) + } + + return startHour, startMinute, endHour, endMinute +} + +///////////////////////////////////////////////////////////////////////////////////// + +//// CalcEndMinuteFirstVideo calculates the need to change the hour (switching one fragment of video recording (which +//// lasts 1 hour) to another fragment of video recording) and returns the number of hours (required number of video +//// fragments), the duration of minutes (the object responsible for the indicator of minutes) of each fragment for the +//// formation of the final video (except for the last video fragment, provided DurationHour > 0 (the third object +//// returned by the CalcEndMinuteFirstVideo function)). +//// +//// In the case that you need to take a full fragment of the video file, for example, from 00-00 to 03-00, the +//// DurationHour value is conciliated by 1 and returned. +//func CalcEndMinuteFirstVideo(durationHour, endMinuteFirstVideo, startHour, endHour, endMinute int) ( +// durationHourCalc int, endMinuteFirstVideoCalc int) { +// durationHour = endHour - startHour +// +// if durationHour > 0 { +// endMinuteFirstVideo = 60 +// } else { +// endMinuteFirstVideo = endMinute +// } +// +// if endMinute == 0 && durationHour > 0 { +// durationHour -= 1 +// } +// +// return durationHour, endMinuteFirstVideo +//} diff --git a/reader/internal/processor/video.go b/reader/internal/processor/video.go new file mode 100644 index 0000000..a5ed64b --- /dev/null +++ b/reader/internal/processor/video.go @@ -0,0 +1,42 @@ +package processor + +//// trimMKV обрезает видеофайл и возвращает название созданного нового файла. +//func trimMKV(inputFile, outputFile, startTime, finishTime string) (outputFileTrimmed string) { +// outputFile = time.Now().Format("15-04-05") + outputFile +// +// cmd := exec.Command("ffmpeg", +// "-i", inputFile, +// "-ss", startTime, +// "-to", finishTime, +// "-c", "copy", +// outputFile) +// +// err := cmd.Run() +// +// if err != nil { +// log.Fatal(err) +// } +// +// log.Println("Видео успешно обрезано") +// return outputFile +//} +// +//// mergeFfmpeg объединяет видеофайлы с помощью ffmpeg +//func mergeFfmpeg(f *os.File) error { +// cmd := exec.Command("ffmpeg", +// "-f", "concat", +// "-safe", "0", +// "-i", f.Name(), +// "-c", "copy", +// time.Now().Format("15-04-05")+"_video.mkv") +// +// err := cmd.Run() +// +// if err != nil { +// log.Println("Ошибка исполнения запроса ffmpeg: ", err) +// return err +// } +// +// log.Println("Видео успешно объединено") +// return nil +//} diff --git a/reader/pkg/handlers/handlers.go b/reader/pkg/handlers/handlers.go new file mode 100644 index 0000000..ed206ee --- /dev/null +++ b/reader/pkg/handlers/handlers.go @@ -0,0 +1,45 @@ +package handlers + +import ( + "encoding/json" + "log" + "net/http" + "reader/internal/processor" +) + +type DownloadRequest struct { + Date string `json:"date"` + StartTime string `json:"start_time"` + EndTime string `json:"end_time"` +} + +func Download(w http.ResponseWriter, r *http.Request) { + log.Printf("new download request: %+v\n", r) + + dr := DownloadRequest{} + + err := json.NewDecoder(r.Body).Decode(&dr) + if err != nil { + log.Printf("json decode error: %v\n", err) + w.WriteHeader(http.StatusBadRequest) + return + } + + pathFileNameRes, err := processor.Process(dr.Date, dr.StartTime, dr.EndTime) + if err != nil { + log.Printf("process error: %v\n", err) + w.WriteHeader(http.StatusBadRequest) + return + } + + w.Header().Set("Content-Type", "video/mp4") + // Разрешаем частичную загрузку (поддержка перемотки) + w.Header().Set("Accept-Ranges", "bytes") + + http.ServeFile(w, r, pathFileNameRes) +} + +func HLS(w http.ResponseWriter, r *http.Request) { + log.Printf("new hls request: %+v\n", r) + +} diff --git a/reader/server/cmd/main.go b/reader/server/cmd/main.go deleted file mode 100644 index 7905807..0000000 --- a/reader/server/cmd/main.go +++ /dev/null @@ -1,5 +0,0 @@ -package main - -func main() { - -} diff --git a/reader/server/go.mod b/reader/server/go.mod deleted file mode 100644 index e45b76e..0000000 --- a/reader/server/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module server - -go 1.23 diff --git a/reader/server/pkg/handlers/handler.go b/reader/server/pkg/handlers/handler.go deleted file mode 100644 index 5502f4b..0000000 --- a/reader/server/pkg/handlers/handler.go +++ /dev/null @@ -1,33 +0,0 @@ -package main - -import ( - "log" - "net/http" - "os" -) - -func serveVideo(w http.ResponseWriter, r *http.Request) { - filePath := "files/111.mp4" - - // Открытие запрашиваемого файла - file, err := os.Open(filePath) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - log.Fatalln("Ошибка открытия файла: ", err) - return - } - defer func() { - err = file.Close() - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - log.Fatalln("Ошибка закрытия файла: ", err) - return - } - }() - - w.Header().Set("Content-Type", "video/mp4") - // Разрешаем частичную загрузку (поддержка перемотки) - w.Header().Set("Accept-Ranges", "bytes") - - http.ServeFile(w, r, filePath) -} diff --git a/reader/video_processor/cmd/main.go b/reader/video_processor/cmd/main.go deleted file mode 100644 index b6ae0e5..0000000 --- a/reader/video_processor/cmd/main.go +++ /dev/null @@ -1,584 +0,0 @@ -package main - -import ( - "fmt" - "log" - "reader/internal/processor" -) - -func main() { - // Определение параметров записи - var date, startTime, endTime string - fmt.Println("Введите дату записи ДД-ММ-ГГГГ:") - fmt.Scan(&date) - fmt.Println("Введите время начала записи ЧЧ-ММ:") - fmt.Scan(&startTime) - fmt.Println("Введите время окончания записи ЧЧ-ММ:") - fmt.Scan(&endTime) - - // Вычисление времени начала и конца, запрошенного фрагмента - startHour, startMinute, endHour, endMinute := processor.CalcNeededTime(startTime, endTime) - - var endMinuteFirstVideo, durationHour int - - // Вычисление длительности (часов) запрошенного фрагмента видеозаписи - durationHour, endMinuteFirstVideo = - processor.CalcEndMinuteFirstVideo(durationHour, endMinuteFirstVideo, startHour, endHour, endMinute) - - // Определение пути хранения видеозаписей - path := "../writer/" - - switch durationHour { - case 0: - processed, created := processor.CreateFile( - startTime, date, path, startMinute, endMinuteFirstVideo, 0) - log.Println("Создан файл: ", processed) - - processor.MergeMKV(created) - processor.DeleteTrimmedFragments(created) - - case 1: - processed, created1 := processor.CreateFile( - startTime, date, path, startMinute, endMinuteFirstVideo, 0) - log.Println("Создан файл: ", processed) - - processed, created2 := processor.CreateFile( - processed, date, path, startMinute, endMinute, durationHour) - log.Println("Создан файл: ", processed) - - processor.MergeMKV(created1, created2) - processor.DeleteTrimmedFragments(created1, created2) - - case 2: - processed, created1 := processor.CreateFile( - startTime, date, path, startMinute, endMinuteFirstVideo, 0) - log.Println("Создан файл: ", processed) - - processed, created2 := processor.CreateFile( - processed, date, path, startMinute, endMinuteFirstVideo, durationHour) - log.Println("Создан файл: ", processed) - - processed, created3 := processor.CreateFile( - processed, date, path, startMinute, endMinute, durationHour) - log.Println("Создан файл: ", processed) - - processor.MergeMKV(created1, created2, created3) - processor.DeleteTrimmedFragments(created1, created2, created3) - - case 3: - created := "" - - processed, created1 := processor.CreateFile( - startTime, date, path, startMinute, endMinuteFirstVideo, 0) - log.Println("Создан файл: ", processed) - - createdS := make([]string, 4) - createdS[0] = created1 - - for i := 1; i <= 2; i++ { - processed, created = processor.CreateFile( - processed, date, path, startMinute, endMinuteFirstVideo, durationHour) - log.Println("Создан файл: ", processed) - - createdS[i] = created - } - - processed, created4 := processor.CreateFile( - processed, date, path, startMinute, endMinute, durationHour) - log.Println("Создан файл: ", processed) - - createdS[3] = created4 - - processor.MergeMKV(createdS...) - processor.DeleteTrimmedFragments(createdS...) - - case 4: - created := "" - - processed, created1 := processor.CreateFile( - startTime, date, path, startMinute, endMinuteFirstVideo, 0) - log.Println("Создан файл: ", processed) - - createdS := make([]string, 5) - createdS[0] = created1 - - for i := 1; i <= 3; i++ { - processed, created = processor.CreateFile( - processed, date, path, startMinute, endMinuteFirstVideo, durationHour) - log.Println("Создан файл: ", processed) - - createdS[i] = created - } - - processed, created5 := processor.CreateFile( - processed, date, path, startMinute, endMinute, durationHour) - log.Println("Создан файл: ", processed) - - createdS[4] = created5 - - processor.MergeMKV(createdS...) - processor.DeleteTrimmedFragments(createdS...) - - case 5: - created := "" - - processed, created1 := processor.CreateFile( - startTime, date, path, startMinute, endMinuteFirstVideo, 0) - log.Println("Создан файл: ", processed) - - createdS := make([]string, 6) - createdS[0] = created1 - - for i := 1; i <= 4; i++ { - processed, created = processor.CreateFile( - processed, date, path, startMinute, endMinuteFirstVideo, durationHour) - log.Println("Создан файл: ", processed) - - createdS[i] = created - } - - processed, created6 := processor.CreateFile( - processed, date, path, startMinute, endMinute, durationHour) - log.Println("Создан файл: ", processed) - - createdS[5] = created6 - - processor.MergeMKV(createdS...) - processor.DeleteTrimmedFragments(createdS...) - - case 6: - created := "" - - processed, created1 := processor.CreateFile( - startTime, date, path, startMinute, endMinuteFirstVideo, 0) - log.Println("Создан файл: ", processed) - - createdS := make([]string, 7) - createdS[0] = created1 - - for i := 1; i <= 5; i++ { - processed, created = processor.CreateFile( - processed, date, path, startMinute, endMinuteFirstVideo, durationHour) - log.Println("Создан файл: ", processed) - - createdS[i] = created - } - - processed, created7 := processor.CreateFile(processed, date, path, startMinute, endMinute, durationHour) - log.Println("Создан файл: ", processed) - - createdS[6] = created7 - - processor.MergeMKV(createdS...) - processor.DeleteTrimmedFragments(createdS...) - - case 7: - created := "" - - processed, created1 := processor.CreateFile(startTime, date, path, startMinute, endMinuteFirstVideo, 0) - log.Println("Создан файл: ", processed) - - createdS := make([]string, 8) - createdS[0] = created1 - - for i := 1; i <= 6; i++ { - processed, created = processor.CreateFile(processed, date, path, startMinute, endMinuteFirstVideo, durationHour) - log.Println("Создан файл: ", processed) - - createdS[i] = created - } - - processed, created8 := processor.CreateFile(processed, date, path, startMinute, endMinute, durationHour) - log.Println("Создан файл: ", processed) - - createdS[7] = created8 - - processor.MergeMKV(createdS...) - processor.DeleteTrimmedFragments(createdS...) - - case 8: - created := "" - - processed, created1 := processor.CreateFile(startTime, date, path, startMinute, endMinuteFirstVideo, 0) - log.Println("Создан файл: ", processed) - - createdS := make([]string, 9) - createdS[0] = created1 - - for i := 1; i <= 7; i++ { - processed, created = processor.CreateFile(processed, date, path, startMinute, endMinuteFirstVideo, durationHour) - log.Println("Создан файл: ", processed) - - createdS[i] = created - } - - processed, created9 := processor.CreateFile(processed, date, path, startMinute, endMinute, durationHour) - log.Println("Создан файл: ", processed) - - createdS[8] = created9 - - processor.MergeMKV(createdS...) - processor.DeleteTrimmedFragments(createdS...) - - case 9: - created := "" - - processed, created1 := processor.CreateFile(startTime, date, path, startMinute, endMinuteFirstVideo, 0) - log.Println("Создан файл: ", processed) - - createdS := make([]string, 10) - createdS[0] = created1 - - for i := 1; i <= 8; i++ { - processed, created = processor.CreateFile(processed, date, path, startMinute, endMinuteFirstVideo, durationHour) - log.Println("Создан файл: ", processed) - - createdS[i] = created - } - - processed, created10 := processor.CreateFile(processed, date, path, startMinute, endMinute, durationHour) - log.Println("Создан файл: ", processed) - - createdS[9] = created10 - - processor.MergeMKV(createdS...) - processor.DeleteTrimmedFragments(createdS...) - - case 10: - created := "" - - processed, created1 := processor.CreateFile(startTime, date, path, startMinute, endMinuteFirstVideo, 0) - log.Println("Создан файл: ", processed) - - createdS := make([]string, 11) - createdS[0] = created1 - - for i := 1; i <= 9; i++ { - processed, created = processor.CreateFile(processed, date, path, startMinute, endMinuteFirstVideo, durationHour) - log.Println("Создан файл: ", processed) - - createdS[i] = created - } - - processed, created11 := processor.CreateFile(processed, date, path, startMinute, endMinute, durationHour) - log.Println("Создан файл: ", processed) - - createdS[10] = created11 - - processor.MergeMKV(createdS...) - processor.DeleteTrimmedFragments(createdS...) - - case 11: - created := "" - - processed, created1 := processor.CreateFile(startTime, date, path, startMinute, endMinuteFirstVideo, 0) - log.Println("Создан файл: ", processed) - - createdS := make([]string, 12) - createdS[0] = created1 - - for i := 1; i <= 10; i++ { - processed, created = processor.CreateFile(processed, date, path, startMinute, endMinuteFirstVideo, durationHour) - log.Println("Создан файл: ", processed) - - createdS[i] = created - } - - processed, created12 := processor.CreateFile(processed, date, path, startMinute, endMinute, durationHour) - log.Println("Создан файл: ", processed) - - createdS[11] = created12 - - processor.MergeMKV(createdS...) - processor.DeleteTrimmedFragments(createdS...) - - case 12: - created := "" - - processed, created1 := processor.CreateFile(startTime, date, path, startMinute, endMinuteFirstVideo, 0) - log.Println("Создан файл: ", processed) - - createdS := make([]string, 13) - createdS[0] = created1 - - for i := 1; i <= 11; i++ { - processed, created = processor.CreateFile(processed, date, path, startMinute, endMinuteFirstVideo, durationHour) - log.Println("Создан файл: ", processed) - - createdS[i] = created - } - - processed, created13 := processor.CreateFile(processed, date, path, startMinute, endMinute, durationHour) - log.Println("Создан файл: ", processed) - - createdS[12] = created13 - - processor.MergeMKV(createdS...) - processor.DeleteTrimmedFragments(createdS...) - - case 13: - created := "" - - processed, created1 := processor.CreateFile(startTime, date, path, startMinute, endMinuteFirstVideo, 0) - log.Println("Создан файл: ", processed) - - createdS := make([]string, 14) - createdS[0] = created1 - - for i := 1; i <= 12; i++ { - processed, created = processor.CreateFile(processed, date, path, startMinute, endMinuteFirstVideo, durationHour) - log.Println("Создан файл: ", processed) - - createdS[i] = created - } - - processed, created14 := processor.CreateFile(processed, date, path, startMinute, endMinute, durationHour) - log.Println("Создан файл: ", processed) - - createdS[13] = created14 - - processor.MergeMKV(createdS...) - processor.DeleteTrimmedFragments(createdS...) - - case 14: - created := "" - - processed, created1 := processor.CreateFile(startTime, date, path, startMinute, endMinuteFirstVideo, 0) - log.Println("Создан файл: ", processed) - - createdS := make([]string, 15) - createdS[0] = created1 - - for i := 1; i <= 13; i++ { - processed, created = processor.CreateFile(processed, date, path, startMinute, endMinuteFirstVideo, durationHour) - log.Println("Создан файл: ", processed) - - createdS[i] = created - } - - processed, created15 := processor.CreateFile(processed, date, path, startMinute, endMinute, durationHour) - log.Println("Создан файл: ", processed) - - createdS[14] = created15 - - processor.MergeMKV(createdS...) - processor.DeleteTrimmedFragments(createdS...) - - case 15: - created := "" - - processed, created1 := processor.CreateFile(startTime, date, path, startMinute, endMinuteFirstVideo, 0) - log.Println("Создан файл: ", processed) - - createdS := make([]string, 16) - createdS[0] = created1 - - for i := 1; i <= 14; i++ { - processed, created = processor.CreateFile(processed, date, path, startMinute, endMinuteFirstVideo, durationHour) - log.Println("Создан файл: ", processed) - - createdS[i] = created - } - - processed, created16 := processor.CreateFile(processed, date, path, startMinute, endMinute, durationHour) - log.Println("Создан файл: ", processed) - - createdS[15] = created16 - - processor.MergeMKV(createdS...) - processor.DeleteTrimmedFragments(createdS...) - - case 16: - created := "" - - processed, created1 := processor.CreateFile(startTime, date, path, startMinute, endMinuteFirstVideo, 0) - log.Println("Создан файл: ", processed) - - createdS := make([]string, 17) - createdS[0] = created1 - - for i := 1; i <= 15; i++ { - processed, created = processor.CreateFile(processed, date, path, startMinute, endMinuteFirstVideo, durationHour) - log.Println("Создан файл: ", processed) - - createdS[i] = created - } - - processed, created17 := processor.CreateFile(processed, date, path, startMinute, endMinute, durationHour) - log.Println("Создан файл: ", processed) - - createdS[16] = created17 - - processor.MergeMKV(createdS...) - processor.DeleteTrimmedFragments(createdS...) - - case 17: - created := "" - - processed, created1 := processor.CreateFile(startTime, date, path, startMinute, endMinuteFirstVideo, 0) - log.Println("Создан файл: ", processed) - - createdS := make([]string, 18) - createdS[0] = created1 - - for i := 1; i <= 16; i++ { - processed, created = processor.CreateFile(processed, date, path, startMinute, endMinuteFirstVideo, durationHour) - log.Println("Создан файл: ", processed) - - createdS[i] = created - } - - processed, created18 := processor.CreateFile(processed, date, path, startMinute, endMinute, durationHour) - log.Println("Создан файл: ", processed) - - createdS[17] = created18 - - processor.MergeMKV(createdS...) - processor.DeleteTrimmedFragments(createdS...) - - case 18: - created := "" - - processed, created1 := processor.CreateFile(startTime, date, path, startMinute, endMinuteFirstVideo, 0) - log.Println("Создан файл: ", processed) - - createdS := make([]string, 19) - createdS[0] = created1 - - for i := 1; i <= 17; i++ { - processed, created = processor.CreateFile(processed, date, path, startMinute, endMinuteFirstVideo, durationHour) - log.Println("Создан файл: ", processed) - - createdS[i] = created - } - - processed, created19 := processor.CreateFile(processed, date, path, startMinute, endMinute, durationHour) - log.Println("Создан файл: ", processed) - - createdS[18] = created19 - - processor.MergeMKV(createdS...) - processor.DeleteTrimmedFragments(createdS...) - - case 19: - created := "" - - processed, created1 := processor.CreateFile(startTime, date, path, startMinute, endMinuteFirstVideo, 0) - log.Println("Создан файл: ", processed) - - createdS := make([]string, 20) - createdS[0] = created1 - - for i := 1; i <= 18; i++ { - processed, created = processor.CreateFile(processed, date, path, startMinute, endMinuteFirstVideo, durationHour) - log.Println("Создан файл: ", processed) - - createdS[i] = created - } - - processed, created20 := processor.CreateFile(processed, date, path, startMinute, endMinute, durationHour) - log.Println("Создан файл: ", processed) - - createdS[19] = created20 - - processor.MergeMKV(createdS...) - processor.DeleteTrimmedFragments(createdS...) - - case 20: - created := "" - - processed, created1 := processor.CreateFile(startTime, date, path, startMinute, endMinuteFirstVideo, 0) - log.Println("Создан файл: ", processed) - - createdS := make([]string, 21) - createdS[0] = created1 - - for i := 1; i <= 19; i++ { - processed, created = processor.CreateFile(processed, date, path, startMinute, endMinuteFirstVideo, durationHour) - log.Println("Создан файл: ", processed) - - createdS[i] = created - } - - processed, created21 := processor.CreateFile(processed, date, path, startMinute, endMinute, durationHour) - log.Println("Создан файл: ", processed) - - createdS[20] = created21 - - processor.MergeMKV(createdS...) - processor.DeleteTrimmedFragments(createdS...) - - case 21: - created := "" - - processed, created1 := processor.CreateFile(startTime, date, path, startMinute, endMinuteFirstVideo, 0) - log.Println("Создан файл: ", processed) - - createdS := make([]string, 22) - createdS[0] = created1 - - for i := 1; i <= 20; i++ { - processed, created = processor.CreateFile(processed, date, path, startMinute, endMinuteFirstVideo, durationHour) - log.Println("Создан файл: ", processed) - - createdS[i] = created - } - - processed, created22 := processor.CreateFile(processed, date, path, startMinute, endMinute, durationHour) - log.Println("Создан файл: ", processed) - - createdS[21] = created22 - - processor.MergeMKV(createdS...) - processor.DeleteTrimmedFragments(createdS...) - - case 22: - created := "" - - processed, created1 := processor.CreateFile(startTime, date, path, startMinute, endMinuteFirstVideo, 0) - log.Println("Создан файл: ", processed) - - createdS := make([]string, 23) - createdS[0] = created1 - - for i := 1; i <= 21; i++ { - processed, created = processor.CreateFile(processed, date, path, startMinute, endMinuteFirstVideo, durationHour) - log.Println("Создан файл: ", processed) - - createdS[i] = created - } - - processed, created23 := processor.CreateFile(processed, date, path, startMinute, endMinute, durationHour) - log.Println("Создан файл: ", processed) - - createdS[22] = created23 - - processor.MergeMKV(createdS...) - processor.DeleteTrimmedFragments(createdS...) - - case 23: - created := "" - - processed, created1 := processor.CreateFile(startTime, date, path, startMinute, endMinuteFirstVideo, 0) - log.Println("Создан файл: ", processed) - - createdS := make([]string, 24) - createdS[0] = created1 - - for i := 1; i <= 22; i++ { - processed, created = processor.CreateFile(processed, date, path, startMinute, endMinuteFirstVideo, durationHour) - log.Println("Создан файл: ", processed) - - createdS[i] = created - } - - processed, created24 := processor.CreateFile(processed, date, path, startMinute, endMinute, durationHour) - log.Println("Создан файл: ", processed) - - createdS[23] = created24 - - processor.MergeMKV(createdS...) - processor.DeleteTrimmedFragments(createdS...) - } - -} diff --git a/reader/video_processor/go.mod b/reader/video_processor/go.mod deleted file mode 100644 index 0a39802..0000000 --- a/reader/video_processor/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module reader - -go 1.23.6 diff --git a/reader/video_processor/internal/processor/file.go b/reader/video_processor/internal/processor/file.go deleted file mode 100644 index 38b5ae2..0000000 --- a/reader/video_processor/internal/processor/file.go +++ /dev/null @@ -1,215 +0,0 @@ -package processor - -import ( - "errors" - "io" - "log" - "os" - "path/filepath" - "strconv" - "time" -) - -// Функция copyFile находит файл в репозитории и создает его копию. -func copyFiles(path string, filename []string) (filenameCopied []string, err error) { - for i := 0; i < len(filename); i++ { - input, err := os.Open(path + filename[i]) - if err != nil { - log.Println("Ошибка открытия input файла: ", err) - } - defer func() { - err = input.Close() - if err != nil { - log.Println("Ошибка закрытия input файла.") - } - }() - - output, err := os.Create(time.Now().Format("15-04-05") + "video.mkv") - if err != nil { - log.Println("Ошибка создания output файла: ", err) - } - defer func() { - err = output.Close() - if err != nil { - log.Println("Ошибка закрытия output файла.") - } - - }() - - _, err = io.Copy(output, input) - if err != nil { - log.Println("Ошибка копирования файла") - } - } - - log.Println("Файлы скопированы.") - return filename, err -} - -// MergeMKV принимает названия видеофайлов для объединения. -func MergeMKV(filenames ...string) { - // Создание файла со списком видеофайлов для объединения - f, err := os.Create("videoList.txt") - if err != nil { - log.Fatalln("Ошибка создания файла со списком видеофайлов для объединения", err) - } - defer func() { - err = f.Close() - if err != nil { - log.Fatalln("Ошибка закрытия файла: ", err.Error()) - } - }() - - // Запись видеофайлов для объединения - n := len(filenames) - - for i := 0; i < n; i++ { - _, err = f.WriteString("file '" + filenames[i] + "'\n") - if err != nil { - log.Fatalln(err) - } - } - - err = mergeFfmpeg(f) - if err != nil { - log.Fatalln("Ошибка объединения видеофайлов с помощью ffmpeg: ", err) - } - - err = os.Remove("videoList.txt") - if err != nil { - log.Println("Ошибка удаления временного файла videoList.txt: ", err) - } - log.Println("Временный файл videoList.txt успешно удален") -} - -// DeleteTrimmedFragments удаляет временно созданные файлы. -func DeleteTrimmedFragments(filenames ...string) { - n := len(filenames) - - for i := 0; i < n; i++ { - err := os.Remove(filenames[i]) - if err != nil { - log.Printf("Ошибка удаления временного файла %s: %s", filenames[i], err.Error()) - } - log.Printf("Временный файл %s успешно удален", filenames[i]) - } -} - -// Конвертация времени из формата строки в формат чисел -func partitionTime(time string) (startHour int, startMinute int, err error) { - // Разделение часов и минут - s := []byte(time) - h := []byte{s[0], s[1]} - m := []byte{s[3], s[4]} - - // Преобразование часов и минут в целые числа - startHour, err = strconv.Atoi(string(h)) - if err != nil { - return 0, 0, err - } - startMinute, err = strconv.Atoi(string(m)) - if err != nil { - return 0, 0, err - } - - return startHour, startMinute, nil -} - -// Формирование имени файла -func createFilename(time, date string) (fileName string) { - s := []byte(time) - s[3], s[4] = '0', '0' - fileName = string(s) + "_" + date + ".mkv" - return fileName -} - -// Добавление одного часа к строке в формате ЧЧ-ММ -func addHour(startTime string) (fileName string) { - s := []byte(startTime) - if s[0] == '0' && s[1] == '9' { - s[0] = '1' - s[1] = '0' - } else if s[0] == '1' && s[1] == '9' { - s[0] = '2' - s[1] = '0' - } else { - s[1]++ - } - fileName = string(s) - return fileName -} - -// Проверка наличия файла -func checkFile(path, fileName string) error { - found := false - - err := filepath.Walk(path, func(filePath string, info os.FileInfo, err error) error { - if err != nil { - return err // Возвращаем ошибку, если возникла - } - if !info.IsDir() && info.Name() == fileName { - log.Println("Файл обнаружен:", filePath) - found = true - return filepath.SkipDir // Останавливаем обход после нахождения - } - return nil - }) - - if err != nil { - return err - } - - if !found { - return errors.New("file not found") - } - - return nil -} - -// CreateFile проверяет запрошенное количество часов записи, проверяет существование видеофайла в репозитории, -// отрезает запрашиваемый отрезок файла, возвращает обработанный час записи и название обрезанного файла. -// -// При значении параметра durationHour > 0, в первом вызове функции необходимо вручную выставить durationHour на 0. -func CreateFile(startTime, date, path string, startMinute, endMinute, durationHour int) ( - startTimeCreatedFile string, outputFile string) { - var startM, finishM string - - // Проверка длительности видео - if endMinute == 60 || endMinute == 0 { - finishM = "01:00:00" - } else { - finishM = "00:" + strconv.Itoa(endMinute) + ":00" - } - - // Проверка запрошенного количества часов записи - if durationHour > 0 { - startTime = addHour(startTime) - startM = "00:00:00" - } else { - startM = "00:" + strconv.Itoa(startMinute) + ":00" - } - - // Проверка существования видеофайла в репозитории - filename := createFilename(startTime, date) - - err := checkFile(path, filename) - if err != nil { - log.Fatalln("Ошибка начального файла: ", err) - } - - // Обрезание видеофайла - inputFile := path + filename - - if endMinute == 60 { - - } - - outputFile = trimMKV( - inputFile, - filename, - startM, - finishM, - ) - - return startTime, outputFile -} diff --git a/reader/video_processor/internal/processor/time.go b/reader/video_processor/internal/processor/time.go deleted file mode 100644 index 32277a5..0000000 --- a/reader/video_processor/internal/processor/time.go +++ /dev/null @@ -1,45 +0,0 @@ -package processor - -import "log" - -// CalcNeededTime принимает начальное и конечное время записи, конвертирует временя из формата строки в формат -// числа и возвращает час и минуту начала времени записи, час и минуту конца времени записи. -func CalcNeededTime(startTime, endTime string) (startHour, startMinute, endHour, endMinute int) { - // Расчет требуемого времени записи - startHour, startMinute, err := partitionTime(startTime) - if err != nil { - log.Fatal("Ошибка конвертации: ", err) - } - endHour, endMinute, err = partitionTime(endTime) - if err != nil { - log.Fatal("Ошибка конвертации: ", err) - } - - return startHour, startMinute, endHour, endMinute -} - -// CalcEndMinuteFirstVideo вычисляет необходимость смены часа (переключение одного фрагмента видеозаписи -// (которое длится 1 час) на другой фрагмент видеозаписи) и возвращает количество часов (требуемое количество фрагментов -// видеозаписи), длительность минут (объект, отвечающий за показатель минут) каждого фрагмента для формирования итоговой -// видеозаписи (кроме последнего видеофрагмента, при условии durationHour > 0 (третий объект, возвращаемый функцией -// calcEndMinuteFirstVideo). -// -// В случае, если необходимо взять полный фрагмент видеофайла, например с 00-00 до 03-00, значениеdurationHour будет -// -// снижено на 1 и возвращено. -func CalcEndMinuteFirstVideo(durationHour, endMinuteFirstVideo, startHour, endHour, endMinute int) ( - durationHourCalc int, endMinuteFirstVideoCalc int) { - durationHour = endHour - startHour - - if durationHour > 0 { - endMinuteFirstVideo = 60 - } else { - endMinuteFirstVideo = endMinute - } - - if endMinute == 0 && durationHour > 0 { - durationHour -= 1 - } - - return durationHour, endMinuteFirstVideo -} diff --git a/reader/video_processor/internal/processor/video.go b/reader/video_processor/internal/processor/video.go deleted file mode 100644 index 9ded5a7..0000000 --- a/reader/video_processor/internal/processor/video.go +++ /dev/null @@ -1,49 +0,0 @@ -package processor - -import ( - "log" - "os" - "os/exec" - "time" -) - -// trimMKV обрезает видеофайл и возвращает название созданного нового файла. -func trimMKV(inputFile, outputFile, startTime, finishTime string) (outputFileTrimmed string) { - outputFile = time.Now().Format("15-04-05") + outputFile - - cmd := exec.Command("ffmpeg", - "-i", inputFile, - "-ss", startTime, - "-to", finishTime, - "-c", "copy", - outputFile) - - err := cmd.Run() - - if err != nil { - log.Fatal(err) - } - - log.Println("Видео успешно обрезано") - return outputFile -} - -// mergeFfmpeg объединяет видеофайлы с помощью ffmpeg -func mergeFfmpeg(f *os.File) error { - cmd := exec.Command("ffmpeg", - "-f", "concat", - "-safe", "0", - "-i", f.Name(), - "-c", "copy", - time.Now().Format("15-04-05")+"_video.mkv") - - err := cmd.Run() - - if err != nil { - log.Println("Ошибка исполнения запроса ffmpeg: ", err) - return err - } - - log.Println("Видео успешно объединено") - return nil -}