torrent download implemented

This commit is contained in:
Timon Ringwald 2022-08-23 11:48:26 +02:00
parent 95f77cf189
commit 17ee4822a9
4 changed files with 72 additions and 25 deletions

41
download_torrent_file.go Normal file
View File

@ -0,0 +1,41 @@
package main
import (
"fmt"
"io"
"net/http"
"os"
"path"
"path/filepath"
"git.milar.in/nyaanime/model"
)
func DownloadTorrent(animeEp model.AnimeEpisode, torrent *model.ParsedTorrent) error {
if err := SetAnimeEpDownloading(animeEp); err != nil {
return ErrLockFileCreationFailed.Wrap(err, animeEp.Anime.Title.Romaji, animeEp.Episode)
}
torrentFilePath := filepath.Join(TorrentPath, path.Base(torrent.Torrent.Link))
fmt.Printf("download: %s -> %s\n", torrent.Torrent.Link, torrentFilePath)
resp, err := http.Get(torrent.Torrent.Link)
if err != nil {
return ErrDownloadTorrentFileFailed.Wrap(err, torrent.Torrent.Link)
}
defer resp.Body.Close()
file, err := os.Create(torrentFilePath)
if err != nil {
return ErrSaveTorrentFileFailed.Wrap(err, torrent.Torrent.Link)
}
defer file.Close()
_, err = io.Copy(file, resp.Body)
if err != nil {
return ErrSaveTorrentFileFailed.Wrap(err, torrent.Torrent.Link)
}
return nil
}

View File

@ -14,4 +14,8 @@ var (
ErrInvalidAnimeStatus = adverr.NewErrTmpl("ErrInvalidAnimeStatus", "invalid status '%s' in ANIME_STATUS (allowed: %s)") ErrInvalidAnimeStatus = adverr.NewErrTmpl("ErrInvalidAnimeStatus", "invalid status '%s' in ANIME_STATUS (allowed: %s)")
ErrInvalidGlobSyntax = adverr.NewErrTmpl("ErrInvalidGlobSyntax", "invalid filepath.Glob syntax: '%s'") ErrInvalidGlobSyntax = adverr.NewErrTmpl("ErrInvalidGlobSyntax", "invalid filepath.Glob syntax: '%s'")
ErrNoSuitableFileFound = adverr.NewErrTmpl("ErrNoSuitableFileFound", "no file found with essential properties for anime '%s' and episode %d") ErrNoSuitableFileFound = adverr.NewErrTmpl("ErrNoSuitableFileFound", "no file found with essential properties for anime '%s' and episode %d")
ErrDownloadTorrentFileFailed = adverr.NewErrTmpl("ErrDownloadTorrentFileFailed", "torrent file download failed: %s")
ErrLockFileCreationFailed = adverr.NewErrTmpl("ErrLockFileCreationFailed", "creation of lock file for anime '%s' and episode %d failed")
ErrSaveTorrentFileFailed = adverr.NewErrTmpl("ErrSaveTorrentFileFailed", "torrent file could not be saved: %s")
) )

View File

@ -1,7 +1,7 @@
package main package main
import ( import (
"fmt" "errors"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
@ -27,11 +27,11 @@ func GetAnimeEpFilepath(animeEp model.AnimeEpisode, ext string) string {
if err := AnimeEpFilepathPattern.Execute(b, tmplData); err != nil { if err := AnimeEpFilepathPattern.Execute(b, tmplData); err != nil {
panic(err) panic(err)
} }
return b.String() return filepath.Join(AnimePath, b.String())
} }
func AnimeEpExistsLocally(animeEp model.AnimeEpisode) bool { func AnimeEpExistsLocally(animeEp model.AnimeEpisode) bool {
animeEpPath := filepath.Join(AnimePath, GetAnimeEpFilepath(animeEp, "*")) animeEpPath := GetAnimeEpFilepath(animeEp, "*")
files, err := filepath.Glob(animeEpPath) files, err := filepath.Glob(animeEpPath)
if err != nil { if err != nil {
@ -42,7 +42,7 @@ func AnimeEpExistsLocally(animeEp model.AnimeEpisode) bool {
} }
func GetLocalAnimeEpProperties(animeEp model.AnimeEpisode) (*FilePriority, bool, error) { func GetLocalAnimeEpProperties(animeEp model.AnimeEpisode) (*FilePriority, bool, error) {
animeEpPath := filepath.Join(AnimePath, GetAnimeEpFilepath(animeEp, "*")) animeEpPath := GetAnimeEpFilepath(animeEp, "*")
files, err := filepath.Glob(animeEpPath) files, err := filepath.Glob(animeEpPath)
if err != nil { if err != nil {
return nil, false, ErrInvalidGlobSyntax.Wrap(err, animeEpPath) return nil, false, ErrInvalidGlobSyntax.Wrap(err, animeEpPath)
@ -70,18 +70,17 @@ func GetLocalAnimeEpProperties(animeEp model.AnimeEpisode) (*FilePriority, bool,
return mostPrio, mostPrio != nil, nil return mostPrio, mostPrio != nil, nil
} }
// TODO cache? func IsAnimeEpDownloading(animeEp model.AnimeEpisode) bool {
func TorrentFileDownloading(torrent *model.ParsedTorrent) bool { animeEpPath := GetAnimeEpFilepath(animeEp, "lock")
torrentFile := filepath.Join(TorrentPath, fmt.Sprintf("%s.torrent", torrent.Torrent.ID)) _, err := os.Stat(animeEpPath)
return !errors.Is(err, os.ErrNotExist)
if _, err := os.Stat(torrentFile); err == nil { }
return true
} func SetAnimeEpDownloading(animeEp model.AnimeEpisode) error {
animeEpPath := GetAnimeEpFilepath(animeEp, "lock")
addedTorrentFile := filepath.Join(TorrentPath, fmt.Sprintf("%s.torrent.added", torrent.Torrent.ID)) file, err := os.Create(animeEpPath)
if _, err := os.Stat(addedTorrentFile); err == nil { if err != nil {
return true defer file.Close()
} }
return err
return false
} }

17
main.go
View File

@ -71,6 +71,7 @@ func main() {
fmt.Println("subtitle priorites:", Map2Str(PreferredSubtitles)) fmt.Println("subtitle priorites:", Map2Str(PreferredSubtitles))
fmt.Println("resolution priorites:", Map2Str(PreferredResolutions)) fmt.Println("resolution priorites:", Map2Str(PreferredResolutions))
// TODO ugly code (see issue nyaanime/downloader#1)
if len(AnimeStatus) == 0 { if len(AnimeStatus) == 0 {
AnimeStatus = []anilist.MediaListStatus{ AnimeStatus = []anilist.MediaListStatus{
anilist.MediaListStatusCurrent, anilist.MediaListStatusCurrent,
@ -122,7 +123,9 @@ func checkTorrents() {
} }
for _, torrentPriority := range torrentPriorities { for _, torrentPriority := range torrentPriorities {
if TorrentFileDownloading(torrentPriority.ParsedTorrent) { torrent := torrentPriority.ParsedTorrent
if IsAnimeEpDownloading(animeEp) {
fmt.Printf("%s | CURRENTLY DOWNLOADING\n", FormatTorrentPriority(torrentPriority)) fmt.Printf("%s | CURRENTLY DOWNLOADING\n", FormatTorrentPriority(torrentPriority))
continue continue
} }
@ -132,19 +135,19 @@ func checkTorrents() {
fmt.Printf("%s | LOWER PRIORITY\n", FormatTorrentPriority(torrentPriority)) fmt.Printf("%s | LOWER PRIORITY\n", FormatTorrentPriority(torrentPriority))
} else { } else {
fmt.Printf("%s | HIGHER PRIORITY | STARTING DOWNLOAD\n", FormatTorrentPriority(torrentPriority)) fmt.Printf("%s | HIGHER PRIORITY | STARTING DOWNLOAD\n", FormatTorrentPriority(torrentPriority))
// TODO start download if err := DownloadTorrent(animeEp, torrent); err != nil {
panic(err)
}
} }
} else { } else {
fmt.Printf("%s | NOT IN COLLECTION | STARTING DOWNLOAD\n", FormatTorrentPriority(torrentPriority)) fmt.Printf("%s | NOT IN COLLECTION | STARTING DOWNLOAD\n", FormatTorrentPriority(torrentPriority))
// TODO start download if err := DownloadTorrent(animeEp, torrent); err != nil {
panic(err)
}
} }
// TODO download anime episode with highest priority (first one in slice)
} }
} }
// TODO store preferred properties of downloaded torrents in db
duration := time.Since(start) duration := time.Since(start)
fmt.Printf("\ncheck took %s. sleeping for %s\n", duration.Truncate(time.Millisecond), (PollRate - duration).Truncate(time.Millisecond)) fmt.Printf("\ncheck took %s. sleeping for %s\n", duration.Truncate(time.Millisecond), (PollRate - duration).Truncate(time.Millisecond))
} }