Refactoring, added remaining custom errors

This commit is contained in:
ChaoticByte 2025-03-14 23:20:47 +01:00
parent 424e912f6c
commit ee3518ab5c
No known key found for this signature in database
5 changed files with 77 additions and 36 deletions

View file

@ -3,7 +3,6 @@
package main package main
import ( import (
"errors"
"flag" "flag"
"fmt" "fmt"
"os" "os"
@ -50,12 +49,11 @@ var Arguments struct {
Help bool `json:"-"` Help bool `json:"-"`
VideoInfo bool `json:"-"` VideoInfo bool `json:"-"`
ListFormats bool `json:"-"` ListFormats bool `json:"-"`
UnparsedChapterNum int `json:"chapter_num"` ChapterNum int `json:"chapter_num"`
// Parsed // Parsed
Video core.GtvVideo `json:"-"` Video core.GtvVideo `json:"-"`
StartDuration time.Duration `json:"-"` StartDuration time.Duration `json:"-"`
StopDuration time.Duration `json:"-"` StopDuration time.Duration `json:"-"`
ChapterIdx int `json:"-"`
Ratelimit float64 `json:"-"` Ratelimit float64 `json:"-"`
} }
@ -91,7 +89,7 @@ func CliParseArguments() error {
flag.BoolVar(&Arguments.Help, "help", false, "") flag.BoolVar(&Arguments.Help, "help", false, "")
flag.BoolVar(&Arguments.VideoInfo, "info", false, "") flag.BoolVar(&Arguments.VideoInfo, "info", false, "")
flag.StringVar(&Arguments.Url, "url", "", "") flag.StringVar(&Arguments.Url, "url", "", "")
flag.IntVar(&Arguments.UnparsedChapterNum, "chapter", 0, "") // 0 -> chapter idx -1 -> complete stream flag.IntVar(&Arguments.ChapterNum, "chapter", 0, "") // 0 -> chapter idx -1 -> complete stream
flag.StringVar(&Arguments.FormatName, "format", "auto", "") flag.StringVar(&Arguments.FormatName, "format", "auto", "")
flag.StringVar(&Arguments.OutputFile, "output", "", "") flag.StringVar(&Arguments.OutputFile, "output", "", "")
flag.StringVar(&Arguments.TimestampStart, "start", "", "") flag.StringVar(&Arguments.TimestampStart, "start", "", "")
@ -104,9 +102,6 @@ func CliParseArguments() error {
if err != nil { if err != nil {
return err return err
} }
if Arguments.Video.Category != "streams" {
return errors.New("video category '" + Arguments.Video.Category + "' not supported")
}
if Arguments.TimestampStart == "" { if Arguments.TimestampStart == "" {
Arguments.StartDuration = -1 Arguments.StartDuration = -1
} else { } else {
@ -123,10 +118,9 @@ func CliParseArguments() error {
return err return err
} }
} }
Arguments.ChapterIdx = Arguments.UnparsedChapterNum - 1
Arguments.Ratelimit = ratelimitMbs * 1_000_000.0 // MB/s -> B/s Arguments.Ratelimit = ratelimitMbs * 1_000_000.0 // MB/s -> B/s
if Arguments.Ratelimit <= 0 { if Arguments.Ratelimit <= 0 {
return errors.New("the value of --max-rate must be greater than 0") return &GenericCliAgumentError{Msg: "the value of --max-rate must be greater than 0"}
} }
return err return err
} }
@ -162,13 +156,16 @@ func CliRun() int {
fmt.Print("\n") fmt.Print("\n")
fmt.Printf("Title: %s\n", streamEp.Title) fmt.Printf("Title: %s\n", streamEp.Title)
// Check and list chapters/formats and exit // Check and list chapters/formats and exit
if Arguments.ChapterIdx >= 0 { targetChapter, err := streamEp.GetChapterByNumber(Arguments.ChapterNum)
if Arguments.ChapterIdx >= len(streamEp.Chapters) { if err != nil {
CliErrorMessage(&core.ChapterNotFoundError{ChapterNum: Arguments.UnparsedChapterNum}) CliErrorMessage(err)
CliAvailableChapters(streamEp.Chapters) CliAvailableChapters(streamEp.Chapters)
return 1 return 1
} }
if Arguments.ChapterNum > 0 && len(streamEp.Chapters) > 0 {
fmt.Printf("Chapter: %v. %v\n", Arguments.ChapterNum, targetChapter.Title)
} }
// Video Info
if Arguments.VideoInfo { if Arguments.VideoInfo {
fmt.Printf("Episode: %s\n", streamEp.Episode) fmt.Printf("Episode: %s\n", streamEp.Episode)
fmt.Printf("Length: %s\n", streamEp.Length) fmt.Printf("Length: %s\n", streamEp.Length)
@ -198,22 +195,16 @@ func CliRun() int {
return 1 return 1
} }
fmt.Printf("Format: %v\n", format.Name) fmt.Printf("Format: %v\n", format.Name)
// chapter
targetChapter := core.Chapter{Index: -1} // set Index to -1 for noop
if len(streamEp.Chapters) > 0 && Arguments.ChapterIdx >= 0 {
targetChapter = streamEp.Chapters[Arguments.ChapterIdx]
fmt.Printf("Chapter: %v. %v\n", Arguments.UnparsedChapterNum, targetChapter.Title)
}
// We already set the output file correctly so we can output it // We already set the output file correctly so we can output it
if Arguments.OutputFile == "" { if Arguments.OutputFile == "" {
Arguments.OutputFile = streamEp.GetProposedFilename(Arguments.ChapterIdx) Arguments.OutputFile = streamEp.GetProposedFilename(targetChapter)
} }
// Start Download // Start Download
fmt.Printf("Output: %v\n", Arguments.OutputFile) fmt.Printf("Output: %v\n", Arguments.OutputFile)
fmt.Print("\n") fmt.Print("\n")
successful := false successful := false
aborted := false aborted := false
for p := range core.DownloadEpisode( for p := range core.DownloadStreamEpisode(
streamEp, streamEp,
targetChapter, targetChapter,
Arguments.FormatName, Arguments.FormatName,
@ -242,7 +233,7 @@ func CliRun() int {
fmt.Print("\nAborted. ") fmt.Print("\nAborted. ")
return 130 return 130
} else if !successful { } else if !successful {
CliErrorMessage(errors.New("download failed")) CliErrorMessage(&GenericDownloadError{})
return 1 return 1
} else { return 0 } } else { return 0 }
} }

15
cli/errors.go Normal file
View file

@ -0,0 +1,15 @@
package main
type GenericCliAgumentError struct {
Msg string
}
func (err *GenericCliAgumentError) Error() string {
return err.Msg
}
type GenericDownloadError struct {}
func (err *GenericDownloadError) Error() string {
return "download failed"
}

View file

@ -35,7 +35,7 @@ type FileExistsError struct {
} }
func (err *FileExistsError) Error() string { func (err *FileExistsError) Error() string {
return "File '" + err.Filename + "' already exists. See the available options on how to proceed." return "file '" + err.Filename + "' already exists - see the available options on how to proceed"
} }
type FormatNotFoundError struct { type FormatNotFoundError struct {
@ -43,7 +43,7 @@ type FormatNotFoundError struct {
} }
func (err *FormatNotFoundError) Error() string { func (err *FormatNotFoundError) Error() string {
return "Format " + err.FormatName + " is not available." return "format " + err.FormatName + " is not available"
} }
type ChapterNotFoundError struct { type ChapterNotFoundError struct {
@ -51,5 +51,27 @@ type ChapterNotFoundError struct {
} }
func (err *ChapterNotFoundError) Error() string { func (err *ChapterNotFoundError) Error() string {
return fmt.Sprintf("Chapter %v not found.", err.ChapterNum) return fmt.Sprintf("chapter %v not found", err.ChapterNum)
}
type VideoCategoryUnsupportedError struct {
Category string
}
func (err *VideoCategoryUnsupportedError) Error() string {
return fmt.Sprintf("video category '%v' not supported", err.Category)
}
type GtvVideoUrlParseError struct {
Url string
}
func (err *GtvVideoUrlParseError) Error() string {
return fmt.Sprintf("Could not parse URL %v", err.Url)
}
type DownloadInfoFileReadError struct {}
func (err *DownloadInfoFileReadError) Error() string {
return "could not read download info file, can't continue download"
} }

View file

@ -4,7 +4,6 @@ package core
import ( import (
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"iter" "iter"
@ -113,7 +112,7 @@ func GetStreamChunkList(video VideoFormat) (ChunkList, error) {
return chunklist, err return chunklist, err
} }
func DownloadEpisode( func DownloadStreamEpisode(
ep StreamEpisode, ep StreamEpisode,
chapter Chapter, chapter Chapter,
formatName string, formatName string,
@ -128,7 +127,7 @@ func DownloadEpisode(
return func (yield func(DownloadProgress) bool) { return func (yield func(DownloadProgress) bool) {
// Set automatic values // Set automatic values
if outputFile == "" { if outputFile == "" {
outputFile = ep.GetProposedFilename(chapter.Index) outputFile = ep.GetProposedFilename(chapter)
} }
if chapter.Index >= 0 { if chapter.Index >= 0 {
if startDuration < 0 { if startDuration < 0 {
@ -167,7 +166,7 @@ func DownloadEpisode(
if continueDl { if continueDl {
infoFileData, err := os.ReadFile(infoFilename) infoFileData, err := os.ReadFile(infoFilename)
if err != nil { if err != nil {
yield(DownloadProgress{Error: errors.New("could not access download info file, can't continue download")}) yield(DownloadProgress{Error: &DownloadInfoFileReadError{}})
return return
} }
i, err := strconv.ParseInt(string(infoFileData), 10, 32) i, err := strconv.ParseInt(string(infoFileData), 10, 32)

View file

@ -3,7 +3,6 @@
package core package core
import ( import (
"errors"
"fmt" "fmt"
"regexp" "regexp"
"time" "time"
@ -40,10 +39,13 @@ func ParseGtvVideoUrl(url string) (GtvVideo, error) {
video := GtvVideo{} video := GtvVideo{}
match := videoUrlRegex.FindStringSubmatch(url) match := videoUrlRegex.FindStringSubmatch(url)
if len(match) < 2 { if len(match) < 2 {
return video, errors.New("Could not parse URL " + url) return video, &GtvVideoUrlParseError{Url: url}
} }
video.Category = match[1] video.Category = match[1]
video.Id = match[2] video.Id = match[2]
if video.Category != "streams" {
return video, &VideoCategoryUnsupportedError{Category: video.Category}
}
return video, nil return video, nil
} }
@ -109,9 +111,21 @@ func (ep *StreamEpisode) GetFormatByName(formatName string) (VideoFormat, error)
} }
} }
func (ep *StreamEpisode) GetProposedFilename(chapterIdx int) string { func (ep *StreamEpisode) GetChapterByNumber(number int) (Chapter, error) {
if chapterIdx >= 0 && chapterIdx < len(ep.Chapters) { chapter := Chapter{Index: -1} // set Index to -1 for noop
return fmt.Sprintf("GTV%04s - %v. %s.ts", ep.Episode, chapterIdx+1, sanitizeUnicodeFilename(ep.Chapters[chapterIdx].Title)) idx := number-1
if idx >= 0 && idx >= len(ep.Chapters) {
return chapter, &ChapterNotFoundError{ChapterNum: number}
}
if len(ep.Chapters) > 0 && idx >= 0 {
chapter = ep.Chapters[idx]
}
return chapter, nil
}
func (ep *StreamEpisode) GetProposedFilename(chapter Chapter) string {
if chapter.Index >= 0 && chapter.Index < len(ep.Chapters) {
return fmt.Sprintf("GTV%04s - %v. %s.ts", ep.Episode, chapter.Index, sanitizeUnicodeFilename(ep.Chapters[chapter.Index].Title))
} else { } else {
return sanitizeUnicodeFilename(ep.Title) + ".ts" return sanitizeUnicodeFilename(ep.Title) + ".ts"
} }