feat: save hash instead of link, and refactor torrent download

This commit is contained in:
Simon Ding
2025-02-01 14:22:34 +08:00
parent 8b6558b2b5
commit 2821d49673
18 changed files with 463 additions and 236 deletions

View File

@@ -59,27 +59,55 @@ func (c *Client) reloadTasks() {
}
if dl.Implementation == downloadclients.ImplementationTransmission {
to, err := transmission.NewTorrent(transmission.Config{
URL: dl.URL,
User: dl.User,
Password: dl.Password,
}, t.Link)
if err != nil {
log.Warnf("get task error: %v", err)
continue
if t.Hash != "" { //优先使用hash
to, err := transmission.NewTorrentHash(transmission.Config{
URL: dl.URL,
User: dl.User,
Password: dl.Password,
}, t.Hash)
if err != nil {
log.Warnf("get task error: %v", err)
continue
}
c.tasks[t.ID] = &Task{Torrent: to}
} else if t.Link != "" {
to, err := transmission.NewTorrent(transmission.Config{
URL: dl.URL,
User: dl.User,
Password: dl.Password,
}, t.Link)
if err != nil {
log.Warnf("get task error: %v", err)
continue
}
c.tasks[t.ID] = &Task{Torrent: to}
}
c.tasks[t.ID] = &Task{Torrent: to}
} else if dl.Implementation == downloadclients.ImplementationQbittorrent {
to, err := qbittorrent.NewTorrent(qbittorrent.Info{
URL: dl.URL,
User: dl.User,
Password: dl.Password,
}, t.Link)
if err != nil {
log.Warnf("get task error: %v", err)
continue
if t.Hash != "" {
to, err := qbittorrent.NewTorrentHash(qbittorrent.Info{
URL: dl.URL,
User: dl.User,
Password: dl.Password,
}, t.Hash)
if err != nil {
log.Warnf("get task error: %v", err)
continue
}
c.tasks[t.ID] = &Task{Torrent: to}
} else if t.Link != "" {
to, err := qbittorrent.NewTorrent(qbittorrent.Info{
URL: dl.URL,
User: dl.User,
Password: dl.Password,
}, t.Link)
if err != nil {
log.Warnf("get task error: %v", err)
continue
}
c.tasks[t.ID] = &Task{Torrent: to}
}
c.tasks[t.ID] = &Task{Torrent: to}
}
}

View File

@@ -6,6 +6,7 @@ import (
"polaris/ent"
"polaris/ent/episode"
"polaris/ent/history"
"polaris/ent/media"
"polaris/log"
"polaris/pkg/metadata"
"polaris/pkg/notifier/message"
@@ -16,95 +17,13 @@ import (
)
func (c *Client) DownloadEpisodeTorrent(r1 torznab.Result, seriesId, seasonNum int, episodeNums ...int) (*string, error) {
trc, dlc, err := c.GetDownloadClient()
series, err := c.db.GetMedia(seriesId)
if err != nil {
return nil, errors.Wrap(err, "connect transmission")
}
series := c.db.GetMediaDetails(seriesId)
if series == nil {
return nil, fmt.Errorf("no tv series of id %v", seriesId)
}
//check space available
downloadDir := c.db.GetDownloadDir()
size := utils.AvailableSpace(downloadDir)
if size < uint64(r1.Size) {
log.Errorf("space available %v, space needed %v", size, r1.Size)
return nil, errors.New("no enough space")
}
// magnet, err := utils.Link2Magnet(r1.Link)
// if err != nil {
// return nil, errors.Errorf("converting link to magnet error, link: %v, error: %v", r1.Link, err)
// }
dir := fmt.Sprintf("%s/Season %02d/", series.TargetDir, seasonNum)
if len(episodeNums) > 0 {
for _, epNum := range episodeNums {
var ep *ent.Episode
for _, e := range series.Episodes {
if e.SeasonNumber == seasonNum && e.EpisodeNumber == epNum {
ep = e
}
}
if ep == nil {
return nil, errors.Errorf("no episode of season %d episode %d", seasonNum, epNum)
}
if ep.Status == episode.StatusMissing {
c.db.SetEpisodeStatus(ep.ID, episode.StatusDownloading)
}
}
} else { //season package download
c.db.SetSeasonAllEpisodeStatus(seriesId, seasonNum, episode.StatusDownloading)
}
history, err := c.db.SaveHistoryRecord(ent.History{
MediaID: seriesId,
EpisodeNums: episodeNums,
SeasonNum: seasonNum,
SourceTitle: r1.Name,
TargetDir: dir,
Status: history.StatusRunning,
Size: int(r1.Size),
//Saved: torrent.Save(),
Link: r1.Link,
DownloadClientID: dlc.ID,
IndexerID: r1.IndexerId,
})
if err != nil {
return nil, errors.Wrap(err, "save record")
}
torrent, err := trc.Download(r1.Link, downloadDir)
if err != nil {
return nil, errors.Wrap(err, "downloading")
}
torrent.Start()
c.tasks[history.ID] = &Task{Torrent: torrent}
name := r1.Name
if len(episodeNums) > 0 {
buff := &bytes.Buffer{}
for i, ep := range episodeNums {
if i != 0 {
buff.WriteString(",")
}
buff.WriteString(fmt.Sprint(ep))
}
name = fmt.Sprintf("第%s集 (%s)", buff.String(), name)
} else {
name = fmt.Sprintf("全集 (%s)", name)
}
c.sendMsg(fmt.Sprintf(message.BeginDownload, name))
log.Infof("success add %s to download task", r1.Name)
return &r1.Name, nil
return c.downloadTorrent(series, r1, seasonNum, episodeNums...)
}
/*
@@ -192,53 +111,95 @@ lo:
return torrentNames, nil
}
func (c *Client) DownloadMovie(m *ent.Media, link, name string, size int64, indexerID int) (*string, error) {
func (c *Client) DownloadMovie(m *ent.Media, r1 torznab.Result) (*string, error) {
return c.downloadTorrent(m, r1, 0)
}
func (c *Client) downloadTorrent(m *ent.Media, r1 torznab.Result, seasonNum int, episodeNums ...int) (*string, error) {
trc, dlc, err := c.GetDownloadClient()
if err != nil {
return nil, errors.Wrap(err, "connect transmission")
}
// magnet, err := utils.Link2Magnet(link)
// if err != nil {
// return nil, errors.Errorf("converting link to magnet error, link: %v, error: %v", link, err)
// }
torrent, err := trc.Download(link, c.db.GetDownloadDir())
//check space available
downloadDir := c.db.GetDownloadDir()
size := utils.AvailableSpace(downloadDir)
if size < uint64(r1.Size) {
log.Errorf("space available %v, space needed %v", size, r1.Size)
return nil, errors.New("no enough space")
}
var name = r1.Name
var targetDir = m.TargetDir
if m.MediaType == media.MediaTypeTv { //tv download
targetDir = fmt.Sprintf("%s/Season %02d/", m.TargetDir, seasonNum)
if len(episodeNums) > 0 {
for _, epNum := range episodeNums {
ep, err := c.db.GetEpisode(m.ID, seasonNum, epNum)
if err != nil {
return nil, errors.Errorf("no episode of season %d episode %d", seasonNum, epNum)
}
if ep.Status == episode.StatusMissing {
c.db.SetEpisodeStatus(ep.ID, episode.StatusDownloading)
}
}
buff := &bytes.Buffer{}
for i, ep := range episodeNums {
if i != 0 {
buff.WriteString(",")
}
buff.WriteString(fmt.Sprint(ep))
}
name = fmt.Sprintf("第%s集 (%s)", buff.String(), name)
} else { //season package download
name = fmt.Sprintf("全集 (%s)", name)
c.db.SetSeasonAllEpisodeStatus(m.ID, seasonNum, episode.StatusDownloading)
}
} else {
ep, _ := c.db.GetMovieDummyEpisode(m.ID)
if ep.Status == episode.StatusMissing {
c.db.SetEpisodeStatus(ep.ID, episode.StatusDownloading)
}
}
hash, err := utils.Link2Hash(r1.Link)
if err != nil {
return nil, errors.Wrap(err, "get hash")
}
history, err := c.db.SaveHistoryRecord(ent.History{
MediaID: m.ID,
EpisodeNums: episodeNums,
SeasonNum: seasonNum,
SourceTitle: r1.Name,
TargetDir: targetDir,
Status: history.StatusRunning,
Size: int(r1.Size),
//Saved: torrent.Save(),
Link: r1.Link,
Hash: hash,
DownloadClientID: dlc.ID,
IndexerID: r1.IndexerId,
})
if err != nil {
return nil, errors.Wrap(err, "save record")
}
torrent, err := trc.Download(r1.Link, hash, downloadDir)
if err != nil {
return nil, errors.Wrap(err, "downloading")
}
torrent.Start()
if name == "" {
name = m.OriginalName
}
go func() {
ep, _ := c.db.GetMovieDummyEpisode(m.ID)
history, err := c.db.SaveHistoryRecord(ent.History{
MediaID: m.ID,
EpisodeID: ep.ID,
SourceTitle: name,
TargetDir: m.TargetDir,
Status: history.StatusRunning,
Size: int(size),
//Saved: torrent.Save(),
Link: link,
DownloadClientID: dlc.ID,
IndexerID: indexerID,
})
if err != nil {
log.Errorf("save history error: %v", err)
}
c.tasks[history.ID] = &Task{Torrent: torrent}
if ep.Status == episode.StatusMissing {
c.db.SetEpisodeStatus(ep.ID, episode.StatusDownloading)
}
}()
c.tasks[history.ID] = &Task{Torrent: torrent}
c.sendMsg(fmt.Sprintf(message.BeginDownload, name))
log.Infof("success add %s to download task", name)
return &name, nil
log.Infof("success add %s to download task", r1.Name)
return &r1.Name, nil
}

View File

@@ -101,7 +101,7 @@ func (c *Client) checkTasks() error {
} else if r.Status == history.StatusRunning {
log.Infof("task is done: %v", name)
c.sendMsg(fmt.Sprintf(message.DownloadComplete, name))
go c.postTaskProcessing(id)
go c.postTaskProcessing(id)
}
}
}
@@ -273,7 +273,7 @@ func (c *Client) moveCompletedTask(id int) (err1 error) {
if series == nil {
return nil
}
st := c.db.GetStorage(series.StorageID)
log.Infof("move task files to target dir: %v", r.TargetDir)
stImpl, err := c.GetStorage(st.ID, series.MediaType)
@@ -459,18 +459,15 @@ func (c *Client) DownloadMovieByID(id int) (string, error) {
return "", nil
}
if name, err := c.downloadMovieSingleEpisode(ep, detail.TargetDir); err != nil {
if name, err := c.downloadMovieSingleEpisode(detail.Media, ep); err != nil {
return "", errors.Wrap(err, "download movie")
} else {
return name, nil
}
}
func (c *Client) downloadMovieSingleEpisode(ep *ent.Episode, targetDir string) (string, error) {
trc, dlc, err := c.GetDownloadClient()
if err != nil {
return "", errors.Wrap(err, "connect transmission")
}
func (c *Client) downloadMovieSingleEpisode(m *ent.Media, ep *ent.Episode) (string, error) {
qiangban := c.db.GetSetting(db.SettingAllowQiangban)
allowQiangban := false
if qiangban == "true" {
@@ -484,43 +481,16 @@ func (c *Client) downloadMovieSingleEpisode(ep *ent.Episode, targetDir string) (
FilterQiangban: !allowQiangban,
})
if err != nil {
return "", errors.Wrap(err, "search movie")
}
r1 := res[0]
log.Infof("begin download torrent resource: %v", r1.Name)
magnet, err := utils.Link2Magnet(r1.Link)
s, err := c.downloadTorrent(m, r1, 0)
if err != nil {
return "", errors.Errorf("converting link to magnet error, link: %v, error: %v", r1.Link, err)
return "", err
}
torrent, err := trc.Download(magnet, c.db.GetDownloadDir())
if err != nil {
return "", errors.Wrap(err, "downloading")
}
torrent.Start()
history, err := c.db.SaveHistoryRecord(ent.History{
MediaID: ep.MediaID,
EpisodeID: ep.ID,
SourceTitle: r1.Name,
TargetDir: targetDir,
Status: history.StatusRunning,
Size: int(r1.Size),
//Saved: torrent.Save(),
Link: magnet,
DownloadClientID: dlc.ID,
IndexerID: r1.IndexerId,
})
if err != nil {
log.Errorf("save history error: %v", err)
}
c.tasks[history.ID] = &Task{Torrent: torrent}
c.db.SetEpisodeStatus(ep.ID, episode.StatusDownloading)
return r1.Name, nil
return *s, nil
}
func (c *Client) checkAllSeriesNewSeason() error {

View File

@@ -164,7 +164,13 @@ func (s *Server) DownloadTorrent(c *gin.Context) (interface{}, error) {
return s.core.DownloadEpisodeTorrent(res, in.MediaID, in.Season, in.Episode)
} else {
//movie
return s.core.DownloadMovie(m, in.Link, in.Name, in.Size, in.IndexerId)
name := in.Name
if name == "" {
name = m.OriginalName
}
res := torznab.Result{Name: name, Link: in.Link, Size: in.Size, IndexerId: in.IndexerId}
return s.core.DownloadMovie(m, res)
}
}