diff --git a/check_torrents.go b/check_torrents.go index 0f29901..2b97c94 100644 --- a/check_torrents.go +++ b/check_torrents.go @@ -5,6 +5,7 @@ import ( "time" "git.milar.in/milarin/adverr" + "git.milar.in/nyaanime/model" ) func checkTorrents() { @@ -35,20 +36,45 @@ func checkTorrents() { // filter preferred properties preferredTorrents := GetTorrentsWithMaxPrioByAnimeEp(essentialTorrents) + // information gathered for logging purposes + downloadingEpisodes := map[model.AnimeEpisode]struct{}{} + inCollectionEpisodes := map[model.AnimeEpisode]bool{} + lowerPrioTorrents := map[*model.ParsedTorrent]bool{} + downloadedTorrents := map[model.AnimeEpisode]*TorrentPriority{} + for animeEp, torrentPrio := range preferredTorrents { if IsCurrentlyDownloading(animeEp) { + downloadingEpisodes[animeEp] = struct{}{} continue } - if props, inCollection := GetAnimeEpProps(animeEp); inCollection && props.Priority > torrentPrio.Priority { + props, inCollection := GetAnimeEpProps(animeEp) + lowerPrio := props.Priority > torrentPrio.Priority + + inCollectionEpisodes[animeEp] = inCollection + lowerPrioTorrents[torrentPrio.ParsedTorrent] = lowerPrio + if inCollection && lowerPrio { continue } if err := DownloadTorrent(animeEp, torrentPrio.ParsedTorrent); err != nil { - panic(err) // TODO error handling + fmt.Println(fmt.Sprintf("could not download torrent %s", torrentPrio.ParsedTorrent.Torrent.ID), err) } + + downloadedTorrents[animeEp] = torrentPrio } + ShowDebugInfo( + parsedTorrentsByAnimeEp, + animeListTorrents, + essentialTorrents, + preferredTorrents, + downloadingEpisodes, + inCollectionEpisodes, + lowerPrioTorrents, + downloadedTorrents, + ) + duration := time.Since(start) - fmt.Printf("\ncheck took %s. sleeping for %s\n", duration.Truncate(time.Millisecond), (PollRate - duration).Truncate(time.Millisecond)) + fmt.Printf("check took %s. sleeping for %s\n", duration.Truncate(time.Millisecond), (PollRate - duration).Truncate(time.Millisecond)) } diff --git a/go.mod b/go.mod index b3a520f..351b83d 100644 --- a/go.mod +++ b/go.mod @@ -8,14 +8,19 @@ require ( git.milar.in/milarin/channel v0.0.9 git.milar.in/milarin/envvars/v2 v2.0.0 git.milar.in/milarin/gmath v0.0.2 - git.milar.in/milarin/slices v0.0.2 + git.milar.in/milarin/slices v0.0.3 git.milar.in/nyaanime/model v0.0.0-20220822093541-87208e95e7ac git.milar.in/nyaanime/parsers v0.0.0-20220822100125-2813a7868f6a github.com/PuerkitoBio/goquery v1.8.0 + github.com/fatih/color v1.13.0 gopkg.in/vansante/go-ffprobe.v2 v2.1.0 ) require ( + git.milar.in/milarin/tprint v0.0.6 // indirect github.com/andybalholm/cascadia v1.3.1 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.16 // indirect golang.org/x/net v0.0.0-20220812174116-3211cb980234 // indirect + golang.org/x/sys v0.0.0-20220823224334-20c2bfdbfe24 // indirect ) diff --git a/go.sum b/go.sum index 8eb9866..679c38e 100644 --- a/go.sum +++ b/go.sum @@ -10,6 +10,20 @@ git.milar.in/milarin/gmath v0.0.2 h1:avz+75f8XqAYA1wEB6kis0R5xvRuepBKTqBuJBjh6Yw git.milar.in/milarin/gmath v0.0.2/go.mod h1:HDLftG5RLpiNGKiIWh+O2G1PYkNzyLDADO8Cd/1abiE= git.milar.in/milarin/slices v0.0.2 h1:j92MuP0HWKSaHJMq/FRxDtSDIGiOTvw+KogUTwuulr0= git.milar.in/milarin/slices v0.0.2/go.mod h1:XRNfE99aNKeaPOY1phjOlpIQqeGCW1LOqqh8UHS+vAk= +git.milar.in/milarin/slices v0.0.3 h1:kzaLrE/G4rO2DQq3nVk2TYbuqOsiauLHClVUpgSZM8s= +git.milar.in/milarin/slices v0.0.3/go.mod h1:XRNfE99aNKeaPOY1phjOlpIQqeGCW1LOqqh8UHS+vAk= +git.milar.in/milarin/tprint v0.0.1 h1:ohsQIV8tinBBjUtNXvDBtnH3xZ0F55d6o9i42S+LICY= +git.milar.in/milarin/tprint v0.0.1/go.mod h1:KVwwKRggS88ZePLssFXMdisOzJr1SU8hVEUQDzrVtAA= +git.milar.in/milarin/tprint v0.0.2 h1:K6Qh+3/9IGAJvywKsKKrALLAqIOg2eTr21ZJ6HT4+Ac= +git.milar.in/milarin/tprint v0.0.2/go.mod h1:KVwwKRggS88ZePLssFXMdisOzJr1SU8hVEUQDzrVtAA= +git.milar.in/milarin/tprint v0.0.3 h1:Pq5sG2nm0gDSbdg/uYmpFcFT26oEQBQ62eanV7/wHA0= +git.milar.in/milarin/tprint v0.0.3/go.mod h1:KVwwKRggS88ZePLssFXMdisOzJr1SU8hVEUQDzrVtAA= +git.milar.in/milarin/tprint v0.0.4 h1:SqDKABINQg7qYO/6XQbuydUJM4tEFMlUFMqnZNVAAmo= +git.milar.in/milarin/tprint v0.0.4/go.mod h1:KVwwKRggS88ZePLssFXMdisOzJr1SU8hVEUQDzrVtAA= +git.milar.in/milarin/tprint v0.0.5 h1:T4gszcFME+hW9bwTS/gCelFOwq7aZOX6qTngPiZor7c= +git.milar.in/milarin/tprint v0.0.5/go.mod h1:KVwwKRggS88ZePLssFXMdisOzJr1SU8hVEUQDzrVtAA= +git.milar.in/milarin/tprint v0.0.6 h1:OSiboAnZaeXxx/utZU4nUPSSqamdHYlh89TD02WVOwQ= +git.milar.in/milarin/tprint v0.0.6/go.mod h1:KVwwKRggS88ZePLssFXMdisOzJr1SU8hVEUQDzrVtAA= git.milar.in/nyaanime/model v0.0.0-20220822093541-87208e95e7ac h1:rM5Mpo4/OJuZaBNZdylag+gi8giWVwDbqsoPjhDP9+g= git.milar.in/nyaanime/model v0.0.0-20220822093541-87208e95e7ac/go.mod h1:OzhQgj0b/Hf9fg8VXYxYt8ONQOvHm8xC44TmS9kQ150= git.milar.in/nyaanime/parsers v0.0.0-20220822100125-2813a7868f6a h1:7vrKOL/vpqJ8YFZ9tmq9iPLoBuLnZgptHWaScyFOFFo= @@ -18,11 +32,30 @@ github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0g github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI= github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= +github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= +github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U= +github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E= golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= +golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220823224334-20c2bfdbfe24 h1:TyKJRhyo17yWxOMCTHKWrc5rddHORMlnZ/j57umaUd8= +golang.org/x/sys v0.0.0-20220823224334-20c2bfdbfe24/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 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= diff --git a/main.go b/main.go index 8d75b3f..5bfd760 100644 --- a/main.go +++ b/main.go @@ -6,9 +6,11 @@ import ( ) func main() { - fmt.Println("language priorites:", Map2Str(PreferredLanguages)) - fmt.Println("subtitle priorites:", Map2Str(PreferredSubtitles)) - fmt.Println("resolution priorites:", Map2Str(PreferredResolutions)) + fmt.Println("generated priority values:") + fmt.Print(Map2Table("language", PreferredLanguages)) + fmt.Print(Map2Table("subtitle", PreferredSubtitles)) + fmt.Print(Map2Table("resolution", PreferredResolutions)) + fmt.Println() // get access token once at startup to be sure that an access token is obtainable at all if _, err := GetAnilistAccessToken(); err != nil { diff --git a/nyaa.go b/nyaa.go index 53652d9..5b02737 100644 --- a/nyaa.go +++ b/nyaa.go @@ -15,7 +15,7 @@ import ( var torrentLinkRegex = regexp.MustCompile(`https:\/\/nyaa\.si\/download\/(\d+?)\.torrent`) func GetTorrents() ([]model.Torrent, error) { - resp, err := http.Get("https://nyaa.si/?page=rss&f=0&c=0_0&q=Erai-Raws+ayumu") // TODO https://nyaa.si/?page=rss + resp, err := http.Get("https://nyaa.si/?page=rss") // &f=0&c=0_0&q=Erai-Raws+ayumu" if err != nil { return nil, ErrTorrentNotObtainable.Wrap(err, "torrent data acqusition failed") } diff --git a/show_debug_info.go b/show_debug_info.go new file mode 100644 index 0000000..f71be54 --- /dev/null +++ b/show_debug_info.go @@ -0,0 +1,87 @@ +package main + +import ( + "fmt" + "strings" + + "github.com/fatih/color" + + "git.milar.in/milarin/slices" + "git.milar.in/milarin/tprint" + "git.milar.in/nyaanime/model" +) + +var ( + BoldText = color.New(color.Bold) +) + +func ShowDebugInfo( + parsedTorrentsByAnimeEp, animeListTorrents, essentialTorrents map[model.AnimeEpisode][]*model.ParsedTorrent, + preferredTorrents map[model.AnimeEpisode]*TorrentPriority, + downloadingEpisodes map[model.AnimeEpisode]struct{}, + inCollectionEpisodes map[model.AnimeEpisode]bool, + lowerPrioTorrents map[*model.ParsedTorrent]bool, + downloadedTorrents map[model.AnimeEpisode]*TorrentPriority) { + + for animeEp, parsedTorrents := range parsedTorrentsByAnimeEp { + table := tprint.NewTable("id", "resolution", "languages", "subtitles", "seeders", "leechers", "downloads", "trusted", "evaluation") + + for _, torrent := range parsedTorrents { + eval := getEvaluation( + slices.Contains(essentialTorrents[animeEp], torrent), + preferredTorrents[animeEp] != nil && preferredTorrents[animeEp].ParsedTorrent == torrent, + lowerPrioTorrents[torrent], + downloadedTorrents[animeEp] != nil && downloadedTorrents[animeEp].ParsedTorrent == torrent, + ) + + table.AddRow( + torrent.Torrent.ID, + torrent.Resolution, + strings.Join(torrent.Languages, ", "), + strings.Join(torrent.Subtitles, ", "), + torrent.Torrent.Seeders, + torrent.Torrent.Leechers, + torrent.Torrent.Downloads, + torrent.Torrent.Trusted, + eval, + ) + } + + var epState string + + if _, onList := animeListTorrents[animeEp]; onList { + if _, downloading := downloadingEpisodes[animeEp]; downloading { + epState = color.BlueString("CURRENTLY DOWNLOADING") + } else if inCollectionEpisodes[animeEp] { + epState = color.GreenString("IN COLLECTION") + } else { + epState = color.YellowString("ON LIST") + } + } else { + epState = color.RedString("NOT ON LIST") + } + + header := BoldText.Sprintf( + "%s episode %s (found: %d) (%s)", + color.MagentaString(animeEp.Anime.Title.Romaji), + color.MagentaString("%d", animeEp.Episode), + len(parsedTorrents), epState, + ) + + fmt.Println(tprint.FormatHeaderTable(header, table)) + } +} + +func getEvaluation(essential, preferred, lowerPrio, downloaded bool) string { + if downloaded { + return color.GreenString("DOWNLOAD STARTED") + } else if lowerPrio { + return color.GreenString("collection preferred") + } else if preferred { + return color.BlueString("torrent preferred") + } else if essential { + return color.YellowString("torrent considered") + } else { + return color.RedString("torrent ignored") + } +} diff --git a/utils.go b/utils.go index b520561..eeac1c1 100644 --- a/utils.go +++ b/utils.go @@ -1,12 +1,12 @@ package main import ( - "fmt" + "sort" "strings" "git.milar.in/milarin/anilist" "git.milar.in/milarin/slices" - "git.milar.in/nyaanime/model" + "git.milar.in/milarin/tprint" ) var AllMediaListStatuses = []anilist.MediaListStatus{ @@ -32,55 +32,18 @@ func ParseMediaListStatus(str string) (anilist.MediaListStatus, error) { return s, nil } -func Map2Str[K comparable, T any](m map[K]T) string { - b := new(strings.Builder) +func Map2Table[K comparable](title string, m map[K]int) string { + table := tprint.NewTable(title, "priority") - for k, v := range m { - b.WriteString(fmt.Sprintf("%v:%v ", k, v)) + entries := make([]Pair[K, int], 0, len(m)) + for name, priority := range m { + entries = append(entries, Pair[K, int]{name, priority}) + } + sort.Slice(entries, func(i, j int) bool { return entries[i].Second > entries[j].Second }) + + for _, entry := range entries { + table.AddRow(entry.First, entry.Second) } - str := b.String() - - return str[:len(str)-1] -} - -func FormatTorrentPriority(torrentPriority *TorrentPriority) string { - return fmt.Sprintf("id: %s | resolution: %d | languages: %s | subtitles: %s | seeders: %d | leechers: %d, | downloads: %d | trusted: %t | preferred properties: %s | priority: %d", - torrentPriority.ParsedTorrent.Torrent.ID, - torrentPriority.ParsedTorrent.Resolution, - strings.Join(torrentPriority.ParsedTorrent.Languages, ","), - strings.Join(torrentPriority.ParsedTorrent.Subtitles, ","), - torrentPriority.ParsedTorrent.Torrent.Seeders, - torrentPriority.ParsedTorrent.Torrent.Leechers, - torrentPriority.ParsedTorrent.Torrent.Downloads, - torrentPriority.ParsedTorrent.Torrent.Trusted, - Map2Str(torrentPriority.PreferredProperties), - torrentPriority.Priority, - ) -} - -func FormatFilePriority(animeEp model.AnimeEpisode, props *FilePriority, onList, inCollection bool, torrentCount int) string { - if !onList { - return fmt.Sprintf("\nanime: %s | episode: %d | torrents found: %d | NOT ON LIST\n", - animeEp.Anime.Title.Romaji, - animeEp.Episode, - torrentCount, - ) - } - - if inCollection { - return fmt.Sprintf("\nanime: %s | episode: %d | torrents found: %d | IN COLLECTION | file properties: %s | file priority: %d\n", - animeEp.Anime.Title.Romaji, - animeEp.Episode, - torrentCount, - Map2Str(props.PreferredProperties), - props.Priority, - ) - } - - return fmt.Sprintf("\nanime: %s | episode: %d | torrents found: %d\n", - animeEp.Anime.Title.Romaji, - animeEp.Episode, - torrentCount, - ) + return table.String() }