diff --git a/cmd/crunchyroll-go/cmd/logger.go b/cmd/crunchyroll-go/cmd/logger.go index 1079dc6..d9c7248 100644 --- a/cmd/crunchyroll-go/cmd/logger.go +++ b/cmd/crunchyroll-go/cmd/logger.go @@ -1,19 +1,18 @@ package cmd import ( + "context" "fmt" "io" "log" "os" - "runtime" "strings" - "sync" "time" ) type progress struct { - status bool message string + stop bool } type logger struct { @@ -23,26 +22,21 @@ type logger struct { devView bool - progressWG sync.Mutex - progress chan progress + progress chan progress + done chan interface{} } -func newLogger(debug, info, err bool, color bool) *logger { - debugLog, infoLog, errLog := log.New(io.Discard, "=> ", 0), log.New(io.Discard, "=> ", 0), log.New(io.Discard, "=> ", 0) - - debugColor, infoColor, errColor := "", "", "" - if color && runtime.GOOS != "windows" { - debugColor, infoColor, errColor = "\033[95m", "\033[96m", "\033[31m" - } +func newLogger(debug, info, err bool) *logger { + debugLog, infoLog, errLog := log.New(io.Discard, "➞ ", 0), log.New(io.Discard, "➞ ", 0), log.New(io.Discard, "➞ ", 0) if debug { - debugLog.SetOutput(&loggerWriter{original: os.Stdout, color: debugColor}) + debugLog.SetOutput(os.Stdout) } if info { - infoLog.SetOutput(&loggerWriter{original: os.Stdout, color: infoColor}) + infoLog.SetOutput(os.Stdout) } if err { - errLog.SetOutput(&loggerWriter{original: os.Stdout, color: errColor}) + errLog.SetOutput(os.Stderr) } if debug { @@ -60,140 +54,111 @@ func newLogger(debug, info, err bool, color bool) *logger { } } +func (l *logger) IsDev() bool { + return l.devView +} + +func (l *logger) IsQuiet() bool { + return l.DebugLog.Writer() == io.Discard && l.InfoLog.Writer() == io.Discard && l.ErrLog.Writer() == io.Discard +} + +func (l *logger) Debug(format string, v ...interface{}) { + l.DebugLog.Printf(format, v...) +} + +func (l *logger) Info(format string, v ...interface{}) { + l.InfoLog.Printf(format, v...) +} + +func (l *logger) Err(format string, v ...interface{}) { + l.ErrLog.Printf(format, v...) +} + func (l *logger) Empty() { - if !l.devView && l.InfoLog.Writer() != io.Discard { - fmt.Println() + if l.InfoLog.Writer() != io.Discard { + fmt.Println("") } } -func (l *logger) StartProgress(message string) { - if l.devView { - l.InfoLog.Println(message) +func (l *logger) SetProgress(format string, v ...interface{}) { + if out.InfoLog.Writer() == io.Discard { return } + + message := fmt.Sprintf(format, v...) + + if l.progress != nil { + l.progress <- progress{ + message: message, + stop: false, + } + return + } + l.progress = make(chan progress) + l.done = make(chan interface{}) go func() { states := []string{"-", "\\", "|", "/"} + var count int + for i := 0; ; i++ { - l.progressWG.Lock() + ctx, cancel := context.WithTimeout(context.Background(), 35*time.Millisecond) select { case p := <-l.progress: - // clearing the last line - fmt.Printf("\r%s\r", strings.Repeat(" ", len(l.InfoLog.Prefix())+len(message)+2)) - if p.status { - successTag := "✔" - if runtime.GOOS == "windows" { - successTag = "~" + cancel() + + if p.stop { + if !l.devView { + fmt.Printf("\r" + strings.Repeat(" ", 2+len(message))) + fmt.Printf("\r➞ %s\n", p.message) + } else { + l.Debug(message) } - l.InfoLog.Printf("%s %s", successTag, p.message) + + l.progress = nil + + if count > 0 { + fmt.Printf("↳ %s\n", p.message) + } + + l.done <- nil + return } else { - errorTag := "✘" - if runtime.GOOS == "windows" { - errorTag = "!" + if !l.devView { + fmt.Printf("\r↓ %s\n", message) + } else { + l.Debug(message) } - l.ErrLog.Printf("%s %s", errorTag, p.message) + + l.progress = make(chan progress) + count++ + + if !l.devView { + fmt.Printf("\r" + strings.Repeat(" ", 2+len(message))) + fmt.Printf("\r➞ %s\n", p.message) + } else { + l.Debug(p.message) + } + message = p.message } - l.progress = nil - l.progressWG.Unlock() - return - default: - if i%10 == 0 { - fmt.Printf("\r%s%s %s", l.InfoLog.Prefix(), states[i/10%4], message) + case <-ctx.Done(): + if !l.devView && i%10 == 0 { + fmt.Printf("\r%s %s", states[i/10%4], message) } - time.Sleep(35 * time.Millisecond) - l.progressWG.Unlock() } } }() } -func (l *logger) StartProgressf(message string, a ...interface{}) { - l.StartProgress(fmt.Sprintf(message, a...)) -} - -func (l *logger) EndProgress(successful bool, message string) { - if l.devView { - if successful { - l.InfoLog.Print(message) - } else { - l.ErrLog.Print(message) - } +func (l *logger) StopProgress(format string, v ...interface{}) { + if out.InfoLog.Writer() == io.Discard { return - } else if l.progress != nil { - l.progress <- progress{ - status: successful, - message: message, - } - } -} - -func (l *logger) EndProgressf(successful bool, message string, a ...interface{}) { - l.EndProgress(successful, fmt.Sprintf(message, a...)) -} - -func (l *logger) Debugln(v ...interface{}) { - l.print(0, v...) -} - -func (l *logger) Debugf(message string, a ...interface{}) { - l.print(0, fmt.Sprintf(message, a...)) -} - -func (l *logger) Infoln(v ...interface{}) { - l.print(1, v...) -} - -func (l *logger) Infof(message string, a ...interface{}) { - l.print(1, fmt.Sprintf(message, a...)) -} - -func (l *logger) Errln(v ...interface{}) { - l.print(2, v...) -} - -func (l *logger) Errf(message string, a ...interface{}) { - l.print(2, fmt.Sprintf(message, a...)) -} - -func (l *logger) Fatalln(v ...interface{}) { - l.print(2, v...) - os.Exit(1) -} - -func (l *logger) Fatalf(message string, a ...interface{}) { - l.print(2, fmt.Sprintf(message, a...)) - os.Exit(1) -} - -func (l *logger) print(level int, v ...interface{}) { - if l.progress != nil { - l.progressWG.Lock() - defer l.progressWG.Unlock() - fmt.Print("\r") } - switch level { - case 0: - l.DebugLog.Print(v...) - case 1: - l.InfoLog.Print(v...) - case 2: - l.ErrLog.Print(v...) + l.progress <- progress{ + message: fmt.Sprintf(format, v...), + stop: true, } -} - -type loggerWriter struct { - io.Writer - - original io.Writer - color string -} - -func (lw *loggerWriter) Write(p []byte) (n int, err error) { - if lw.color != "" { - p = append([]byte(lw.color), p...) - p = append(p, []byte("\033[0m")...) - } - return lw.original.Write(p) + <-l.done }