/
stream.go
106 lines (86 loc) · 1.92 KB
/
stream.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package main
import (
"bufio"
"fmt"
"io"
"log"
"regexp"
"strings"
)
var durationRegexp = regexp.MustCompile(`\s?Duration: [\d]+:[\d]+:[\d]+`)
func durationFromSeconds(value uint64) string {
hours := value / 3600
minutes := (value - hours*3600) / 60
seconds := value - (hours*3600 + minutes*60)
return fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds)
}
type Position struct {
nanos uint64
seconds uint64
}
func (p *Position) Set(value uint64) {
p.nanos = value
p.seconds = value / 1000000
}
func (p *Position) String() string {
return durationFromSeconds(p.seconds)
}
type Stream struct {
duration uint64
pos Position
}
func NewStream() *Stream {
return &Stream{
pos: Position{},
duration: 0,
}
}
func (s *Stream) Start(stdout, stderr io.Reader) {
s.duration = 0
s.pos.Set(0)
// Most meta information comes from STDERR
go func() {
scanner := bufio.NewScanner(stderr)
for scanner.Scan() {
line := scanner.Text()
if s.parseDuration(line) {
break
}
}
}()
progress := bufio.NewReader(stdout)
for {
data, err := progress.ReadBytes('\r')
if err != nil {
log.Println("ERROR:", err)
break
}
s.parsePosition(string(data))
}
}
func (s *Stream) parseDuration(line string) bool {
// It must match the output format "Duration: hh:mm:ss"
if !durationRegexp.MatchString(line) {
return false
}
// There's a bunch of junk at the beginning of the string
line = strings.TrimSpace(line)
// Read duration values
var hours, minutes, seconds int
_, err := fmt.Sscanf(line, "Duration: %d:%d:%d", &hours, &minutes, &seconds)
if err != nil {
fmt.Println("Cant parse duration line:", err)
return true
}
s.duration = uint64(seconds + minutes*60 + hours*3600)
return true
}
func (s *Stream) parsePosition(line string) {
if !strings.HasPrefix(line, "M:") {
return
}
var posNanos uint64
if n, _ := fmt.Sscanf(line, "M:%d", &posNanos); n == 1 {
s.pos.Set(posNanos)
}
}