@@ -12,8 +12,13 @@ import (
1212)
1313
1414var (
15- inputPath string
16- shift int32
15+ inputPath string
16+ shift int
17+ from int
18+ to int
19+ fromStr string
20+ toStr string
21+ fileShifted int
1722)
1823
1924var version = "1.0.0"
@@ -24,25 +29,108 @@ func init() {
2429 flaggy .DefaultParser .ShowHelpOnUnexpected = true
2530 flaggy .DefaultParser .AdditionalHelpPrepend = "https://github.com/Nigh/subtitle-ass-shifter"
2631 flaggy .AddPositionalValue (& inputPath , "path" , 1 , true , "the subtitle path to shift" )
27- flaggy .Int32 (& shift , "t" , "shift" , "shift ms" )
32+ flaggy .Int (& shift , "t" , "shift" , "shift ms" )
33+ flaggy .String (& fromStr , "s" , "start" , "start from HH:MM:SS" )
34+ flaggy .String (& toStr , "e" , "end" , "end at HH:MM:SS" )
2835 flaggy .SetVersion (version )
2936 flaggy .Parse ()
3037}
38+
39+ func parseFromTo () error {
40+ re := regexp .MustCompile (`(-?\d+):(\d\d):(\d\d)` )
41+
42+ if fromStr != "" {
43+ matches := re .FindStringSubmatch (fromStr )
44+ if matches == nil {
45+ return fmt .Errorf ("invalid start time format, expected HH:MM:SS, example: 0:23:45" )
46+ }
47+
48+ hours , _ := strconv .Atoi (matches [1 ])
49+ minutes , _ := strconv .Atoi (matches [2 ])
50+ seconds , _ := strconv .Atoi (matches [3 ])
51+
52+ sign := 1
53+ if hours < 0 {
54+ sign = - 1
55+ }
56+ from = (hours * 3600 + minutes * 60 + seconds ) * 1000 * sign
57+ }
58+
59+ if toStr != "" {
60+ matches := re .FindStringSubmatch (toStr )
61+
62+ if matches == nil {
63+ return fmt .Errorf ("invalid end time format, expected HH:MM:SS, example: 1:32:54" )
64+ }
65+ hours , _ := strconv .Atoi (matches [1 ])
66+ minutes , _ := strconv .Atoi (matches [2 ])
67+ seconds , _ := strconv .Atoi (matches [3 ])
68+
69+ sign := 1
70+ if hours < 0 {
71+ sign = - 1
72+ }
73+ to = (hours * 3600 + minutes * 60 + seconds ) * 1000 * sign
74+ }
75+
76+ return nil
77+ }
78+
79+ func timeInclude (t int ) bool {
80+ if from == 0 && to == 0 {
81+ return true
82+ }
83+ if from != 0 && t < from {
84+ return false
85+ }
86+ if to != 0 && t > to {
87+ return false
88+ }
89+ return true
90+ }
91+
3192func main () {
3293 if shift == 0 {
33- fmt .Println ("0ms shift means nothing to do." )
94+ fmt .Println ("shift 0ms means nothing to do." )
3495 return
3596 }
97+ if err := parseFromTo (); err != nil {
98+ fmt .Println (err )
99+ return
100+ }
101+ if to != 0 && from != 0 {
102+ if from > to {
103+ fmt .Println ("end must be greater than start" )
104+ return
105+ }
106+ }
36107 inputPath , _ = filepath .Abs (inputPath )
37108 _ , err := os .Stat (inputPath )
38109 if err != nil {
39110 fmt .Println (err )
40111 return
41112 }
42113 filepath .Walk (inputPath , walker )
114+
115+ if fileShifted > 0 {
116+ fmt .Print ("Total " + strconv .Itoa (fileShifted ) + " files shifted " + strconv .Itoa (shift ) + "ms " )
117+ if from != 0 || to != 0 {
118+ if from != 0 {
119+ fmt .Print ("from " + fromStr )
120+ } else {
121+ fmt .Print ("from start" )
122+ }
123+ if to != 0 {
124+ fmt .Print (" to " + toStr )
125+ } else {
126+ fmt .Print (" to end" )
127+ }
128+ }
129+ fmt .Println ()
130+ }
43131}
44132
45- func srtShift (realPath string , shift int32 ) {
133+ func srtShift (realPath string ) {
46134 srtFile , err := os .ReadFile (realPath )
47135 if err != nil {
48136 fmt .Println (err )
@@ -73,7 +161,10 @@ func srtShift(realPath string, shift int32) {
73161 milliseconds *= sign
74162
75163 totalMs := (hours * 3600 + minutes * 60 + seconds )* 1000 + milliseconds
76- totalMs += int (shift )
164+ if ! timeInclude (totalMs ) {
165+ continue
166+ }
167+ totalMs += shift
77168
78169 if totalMs < 0 {
79170 sign = - 1
@@ -98,10 +189,11 @@ func srtShift(realPath string, shift int32) {
98189 fmt .Println ("[ERROR] " + filepath .Base (realPath ), err )
99190 return
100191 }
101- fmt .Println ("[SUCCESS] Shifted " + strconv .Itoa (int (shift )) + "ms -> " + filepath .Base (realPath ))
192+ fmt .Println ("[SUCCESS] " + filepath .Base (realPath ))
193+ fileShifted ++
102194}
103195
104- func assShift (realPath string , shift int32 ) {
196+ func assShift (realPath string ) {
105197 assFile , err := os .ReadFile (realPath )
106198 if err != nil {
107199 fmt .Println (err )
@@ -132,7 +224,10 @@ func assShift(realPath string, shift int32) {
132224 milliseconds *= sign
133225
134226 totalMs := (hours * 3600 + minutes * 60 + seconds )* 1000 + milliseconds
135- totalMs += int (shift )
227+ if ! timeInclude (totalMs ) {
228+ continue
229+ }
230+ totalMs += shift
136231
137232 if totalMs < 0 {
138233 sign = - 1
@@ -157,7 +252,8 @@ func assShift(realPath string, shift int32) {
157252 fmt .Println ("[ERROR] " + filepath .Base (realPath ), err )
158253 return
159254 }
160- fmt .Println ("[SUCCESS] Shifted " + strconv .Itoa (int (shift )) + "ms -> " + filepath .Base (realPath ))
255+ fmt .Println ("[SUCCESS] " + filepath .Base (realPath ))
256+ fileShifted ++
161257}
162258
163259func walker (realPath string , f os.FileInfo , err error ) error {
@@ -167,9 +263,9 @@ func walker(realPath string, f os.FileInfo, err error) error {
167263 }
168264 switch strings .ToLower (ext ) {
169265 case ".srt" :
170- srtShift (realPath , shift )
266+ srtShift (realPath )
171267 case ".ass" :
172- assShift (realPath , shift )
268+ assShift (realPath )
173269 default :
174270 return nil
175271 }
0 commit comments