tangled
alpha
login
or
join now
arimelody.space
/
vodular
0
fork
atom
Helper tool for stitching together livestream VOD segments and uploading them to YouTube!
0
fork
atom
overview
issues
pulls
pipelines
fix crummy ffprobe json output handling
arimelody.space
1 month ago
51a1de84
f4381f7c
+42
-16
2 changed files
expand all
collapse all
unified
split
main.go
scanner
scanner.go
+14
-10
main.go
···
6
6
"encoding/json"
7
7
"fmt"
8
8
"log"
9
9
+
"math"
9
10
"net/http"
10
11
"os"
11
12
"path"
···
247
248
// concatenate VOD segments into full VOD
248
249
fullVodExists := func () bool {
249
250
// check if full VOD already exists with expected duration
250
250
-
if fullVodProbe, err := scanner.ProbeSegment(video.Filename); err != nil {
251
251
-
var totalLength float64 = 0
252
252
-
for _, filename := range vodFiles {
253
253
-
probe, err := scanner.ProbeSegment(filename)
254
254
-
if err != nil { continue }
255
255
-
totalLength += probe.Format.Duration
256
256
-
}
257
257
-
return fullVodProbe.Format.Duration == totalLength
251
251
+
fullVodProbe, err := scanner.ProbeSegment(video.Filename)
252
252
+
if err != nil { return false }
253
253
+
video.SizeBytes = fullVodProbe.Format.Size
254
254
+
var totalLength float64 = 0
255
255
+
256
256
+
for _, filename := range vodFiles {
257
257
+
probe, err := scanner.ProbeSegment(path.Join(metadata.FootageDir, filename))
258
258
+
if err != nil { continue }
259
259
+
totalLength += probe.Format.Duration
258
260
}
259
259
-
return false
261
261
+
return math.Abs(fullVodProbe.Format.Duration - totalLength) < float64(0.1)
260
262
}()
261
261
-
if !fullVodExists {
263
263
+
if fullVodExists {
264
264
+
log.Print("Full VOD appears to already exist- uploading this file...")
265
265
+
} else {
262
266
video.SizeBytes, err = vid.ConcatVideo(video, vodFiles, verbose)
263
267
if err != nil {
264
268
log.Fatalf("Failed to concatenate VOD segments: %v", err)
+28
-6
scanner/scanner.go
···
4
4
"encoding/json"
5
5
"os"
6
6
"path"
7
7
+
"strconv"
7
8
"strings"
8
9
"time"
9
10
···
28
29
Category *Category `toml:"category" comment:"(Optional) Category details, for additional credits."`
29
30
}
30
31
31
31
-
ffprobeFormat struct {
32
32
+
FFprobeFormat struct {
32
33
Duration float64 `json:"duration"`
33
34
Size int64 `json:"size"`
34
35
}
35
36
36
36
-
ffprobeOutput struct {
37
37
-
Format ffprobeFormat `json:"format"`
37
37
+
FFprobeOutput struct {
38
38
+
Format FFprobeFormat `json:"format"`
38
39
}
39
40
)
40
41
···
58
59
return files, nil
59
60
}
60
61
61
61
-
func ProbeSegment(filename string) (*ffprobeOutput, error) {
62
62
+
func ProbeSegment(filename string) (*FFprobeOutput, error) {
62
63
out, err := ffmpeg_go.Probe(filename)
63
64
if err != nil { return nil, err }
64
65
65
65
-
probe := ffprobeOutput{}
66
66
+
type (
67
67
+
RawFFprobeFormat struct {
68
68
+
// these being strings upsets me immensely
69
69
+
Duration string `json:"duration"`
70
70
+
Size string `json:"size"`
71
71
+
}
72
72
+
RawFFprobeOutput struct {
73
73
+
Format RawFFprobeFormat `json:"format"`
74
74
+
}
75
75
+
)
76
76
+
77
77
+
probe := RawFFprobeOutput{}
66
78
err = json.Unmarshal([]byte(out), &probe)
67
79
if err != nil { return nil, err }
68
80
69
69
-
return &probe, nil
81
81
+
duration, err := strconv.ParseFloat(probe.Format.Duration, 64)
82
82
+
if err != nil { return nil, err }
83
83
+
size, err := strconv.ParseInt(probe.Format.Size, 10, 0)
84
84
+
if err != nil { return nil, err }
85
85
+
86
86
+
return &FFprobeOutput{
87
87
+
Format: FFprobeFormat{
88
88
+
Duration: duration,
89
89
+
Size: size,
90
90
+
},
91
91
+
}, nil
70
92
}
71
93
72
94
func ReadMetadata(directory string) (*Metadata, error) {