-
Notifications
You must be signed in to change notification settings - Fork 1
/
parse.go
88 lines (80 loc) · 2.25 KB
/
parse.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
// Package lrc implements an [LRC format] parser.
// [LRC format]: https://en.wikipedia.org/wiki/LRC_(file_format)
package lrc
import (
"bufio"
"bytes"
"io"
"strings"
"time"
)
// NOTE: The parser simply ignores all unmatched lines and doen't return any parse errors.
type (
// Duration is [time.Duration].
Duration = time.Duration
// Text is [string].
Text = string
)
// Parse parses a byte slice of LRC lyrics.
func Parse(data []byte) ([]Duration, []Text, error) {
return ParseReader(bytes.NewReader(data))
}
// ParseString parses a string of LRC lyrics.
func ParseString(text string) ([]Duration, []Text, error) {
return ParseReader(strings.NewReader(text))
}
func atoi(a byte) byte {
return a - '0'
}
// ParseReader parses the reader according to the [LRC format].
func ParseReader(reader io.Reader) ([]Duration, []Text, error) {
times := make([]Duration, 0)
lines := make([]Text, 0)
scnnr := bufio.NewScanner(reader)
// scnnr.Split(bufio.ScanLines)
for rp := 0; scnnr.Scan(); {
ll := scnnr.Text()
match: // [00:00.00][00:00.00]text -> [00:00.00]text -> text
for {
switch {
case len(ll) >= 10 &&
ll[0] == '[' &&
'0' <= ll[1] && ll[1] <= '9' && '0' <= ll[2] && ll[2] <= '9' &&
ll[3] == ':' &&
'0' <= ll[4] && ll[4] <= '5' && '0' <= ll[5] && ll[5] <= '9' &&
ll[6] == '.' &&
'0' <= ll[7] && ll[7] <= '9' && '0' <= ll[8] && ll[8] <= '9' &&
ll[9] == ']':
// ll -> [00:00.00]
// index -> 0123456789
times = append(times, 0+
Duration(10*atoi(ll[1])+atoi(ll[2]))*time.Minute+
Duration(10*atoi(ll[4])+atoi(ll[5]))*time.Second+
Duration(10*atoi(ll[7])+atoi(ll[8]))*time.Second/100)
ll = ll[10:]
case len(ll) >= 7 &&
ll[0] == '[' &&
'0' <= ll[1] && ll[1] <= '9' && '0' <= ll[2] && ll[2] <= '9' &&
ll[3] == ':' &&
'0' <= ll[4] && ll[4] <= '5' && '0' <= ll[5] && ll[5] <= '9' &&
ll[6] == ']':
// ll -> [00:00]
// index -> 0123456
times = append(times, 0+
Duration(10*atoi(ll[1])+atoi(ll[2]))*time.Minute+
Duration(10*atoi(ll[4])+atoi(ll[5]))*time.Second)
ll = ll[7:]
default:
break match
}
rp++
}
for ; rp > 0; rp-- {
lines = append(lines, ll)
}
}
if err := scnnr.Err(); err != nil {
return nil, nil, err
}
return times, lines, nil
}