diff --git a/go.mod b/go.mod index cfe8a0a..a5a8be6 100644 --- a/go.mod +++ b/go.mod @@ -1,16 +1,20 @@ module github.com/YamiOdymel/chaturbate-dvr -go 1.12 +go 1.19 require ( - github.com/elazarl/goproxy v0.0.0-20210801061803-8e322dfb79c4 // indirect + github.com/TwiN/go-color v1.1.0 github.com/grafov/m3u8 v0.11.1 github.com/parnurzeal/gorequest v0.2.16 - github.com/pkg/errors v0.9.1 // indirect - github.com/smartystreets/goconvey v1.7.2 // indirect - github.com/stretchr/testify v1.7.0 // indirect github.com/teacat/pathx v0.0.0-20201109184104-55ec346a0c6d github.com/urfave/cli/v2 v2.3.0 + github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d // indirect + github.com/elazarl/goproxy v0.0.0-20210801061803-8e322dfb79c4 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/russross/blackfriday/v2 v2.0.1 // indirect + github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect + github.com/smartystreets/goconvey v1.7.2 // indirect + github.com/stretchr/testify v1.7.0 // indirect golang.org/x/net v0.0.0-20211109214657-ef0fda0de508 // indirect moul.io/http2curl v1.0.0 // indirect -) +) \ No newline at end of file diff --git a/go.sum b/go.sum index ab6d7b1..bce1b38 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,12 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/TwiN/go-color v1.1.0 h1:yhLAHgjp2iAxmNjDiVb6Z073NE65yoaPlcki1Q22yyQ= +github.com/TwiN/go-color v1.1.0/go.mod h1:aKVf4e1mD4ai2FtPifkDPP5iyoCwiK08YGzGwerjKo0= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/elazarl/goproxy v0.0.0-20210801061803-8e322dfb79c4 h1:lS3P5Nw3oPO05Lk2gFiYUOL3QPaH+fRoI1wFOc4G1UY= github.com/elazarl/goproxy v0.0.0-20210801061803-8e322dfb79c4/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= -github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 h1:dWB6v3RcOy03t/bUadywsbyrQwCqZeNIEX6M1OtSZOM= github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -40,14 +41,8 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20211109214657-ef0fda0de508 h1:v3NKo+t/Kc3EASxaKZ82lwK6mCf4ZeObQBduYFZHo7c= golang.org/x/net v0.0.0-20211109214657-ef0fda0de508/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= diff --git a/main.go b/main.go index 4d40d0f..87261a6 100644 --- a/main.go +++ b/main.go @@ -13,6 +13,7 @@ import ( "strings" "time" + "github.com/TwiN/go-color" "github.com/teacat/pathx" "github.com/grafov/m3u8" @@ -26,8 +27,8 @@ const chaturbateURL = "https://chaturbate.com/" // retriesAfterOnlined tells the retries for stream when disconnected but not really offlined. var retriesAfterOnlined = 0 -// bucket stores the used segment to prevent fetched the duplicates. -var bucket []string +// temp stores the used segment to prevent fetched the duplicates. +var temp []string // segmentIndex is current stored segment index. var segmentIndex int @@ -41,9 +42,18 @@ var stripQuota int // path save video const savePath = "video" +// error/message handler var ( - errInternal = errors.New("err") - errNoUsername = errors.New("chaturbate-dvr: channel username required with `-u [username]` argument") + errInternal = errors.New("err") + errNoUsername = errors.New("recording: channel username required `-u [USERNAME]` option") + errSegRetFail = color.Colorize(color.Red, ("[FAILED] to fetch the video segments after retried, %s might went offline or is in ticket/privat show.")) + errSegRetFailOnline = color.Colorize(color.Red, ("[FAILED] to fetch the video segments, will try again. [%d/10]")) + infoIsOnline = color.Colorize(color.Green, ("[RECORDING] %s is online! start fetching..")) + infoBackOnline = color.Colorize(color.Green, ("[INFO] %s is back online!")) + infoMergeSegment = color.Colorize(color.Green, ("[INFO] inserting %d segment to the master file. [total: %d]")) + infoSkipped = color.Colorize(color.Blue, ("[INFO] skipped %s due to the empty body!\n")) + infoNotOnline = color.Colorize(color.Gray, ("[INFO] %s is not online, check again in %d minute(s)")) + warningSegment = color.Colorize(color.Yellow, ("[WARNING] cannot find segment %d, will try again. [%d/5]")) ) // roomDossier is the struct to parse the HLS source from the content body. @@ -156,10 +166,10 @@ func watchStream(m3u8Source string, username string, masterFile *os.File, filena // Exit the fetching loop if the channel went offline. if err != nil { if retriesAfterOnlined > 10 { - log.Printf("failed to fetch the video segments after retried, %s might went offline.", username) + log.Printf(errSegRetFail, username) break } else { - log.Printf("failed to fetch the video segments, will try again. (%d/10)", retriesAfterOnlined) + log.Printf(errSegRetFailOnline, retriesAfterOnlined) retriesAfterOnlined++ // Wait to fetch the next playlist. <-time.After(time.Duration(wait*1000) * time.Millisecond) @@ -167,7 +177,7 @@ func watchStream(m3u8Source string, username string, masterFile *os.File, filena } } if retriesAfterOnlined != 0 { - log.Printf("%s is back online!", username) + log.Printf(infoBackOnline, username) retriesAfterOnlined = 0 } for _, v := range chunks { @@ -184,12 +194,12 @@ func watchStream(m3u8Source string, username string, masterFile *os.File, filena // isDuplicateSegment returns true if the segment is already been fetched. func isDuplicateSegment(URI string) bool { - for _, v := range bucket { + for _, v := range temp { if URI[len(URI)-10:] == v { return true } } - bucket = append(bucket, URI[len(URI)-10:]) + temp = append(temp, URI[len(URI)-10:]) return false } @@ -218,7 +228,7 @@ func combineSegment(master *os.File, filename string) { continue } if retry != 0 { - log.Printf("cannot find segment %d, will try again. (%d/5)", index, retry) + log.Printf(warningSegment, index, retry) } retry++ <-time.After(time.Duration(1*retry) * time.Second) @@ -238,9 +248,11 @@ func combineSegment(master *os.File, filename string) { stripIndex++ } master.Write(b) - log.Printf("inserting %d segment to the master file. (total: %d)", index, segmentIndex) // + log.Printf(infoMergeSegment, index, segmentIndex) + e := os.Remove(fmt.Sprintf("./%s/%s~%d.ts", savePath, filename, delete)) + // if e != nil { delete-- } @@ -254,7 +266,7 @@ func fetchSegment(master *os.File, segment *m3u8.MediaSegment, baseURL string, f _, body, _ := gorequest.New().Get(fmt.Sprintf("%s%s", baseURL, segment.URI)).EndBytes() log.Printf("fetching %s (size: %d)\n", segment.URI, len(body)) if len(body) == 0 { - log.Printf("skipped %s due to the empty body!\n", segment.URI) + log.Printf(infoSkipped, segment.URI) return } stripQuota -= len(body) @@ -304,15 +316,15 @@ func endpoint(c *cli.Context) error { for { // Capture the stream if the user is currently online. if getOnlineStatus(c.String("username")) { - log.Printf("%s is online! fetching...", c.String("username")) + log.Printf(infoIsOnline, c.String("username")) capture(c.String("username")) segmentIndex = 0 - bucket = []string{} + temp = []string{} retriesAfterOnlined = 0 continue } // Otherwise we keep checking the channel status until the user is online. - log.Printf("%s is not online, check again after %d minute(s)...", c.String("username"), c.Int("interval")) + log.Printf(infoNotOnline, c.String("username"), c.Int("interval")) <-time.After(time.Minute * time.Duration(c.Int("interval"))) } }