feat: download per media feature

This commit is contained in:
Simon Ding
2024-08-12 10:16:36 +08:00
parent 3c37948798
commit 09ff67fef7
7 changed files with 118 additions and 65 deletions

View File

@@ -57,13 +57,13 @@ func ParseMovie(name string) *MovieMetadata {
// https://en.wikipedia.org/wiki/Pirated_movie_release_types
func isQiangban(name string) bool {
qiangbanFilter := []string{"CAM-Rip", "CAM", "HDCAM", "TS", "HDTS", "TELESYNC", "PDVD", "PreDVDRip", "TC", "HDTC", "TELECINE", "WP", "WORKPRINT"}
qiangbanFilter := []string{"CAMRip","CAM-Rip", "CAM", "HDCAM", "TS","TSRip", "HDTS", "TELESYNC", "PDVD", "PreDVDRip", "TC", "HDTC", "TELECINE", "WP", "WORKPRINT"}
re := regexp.MustCompile(`\W`)
name = re.ReplaceAllString(strings.ToLower(name), " ")
fields := strings.Fields(name)
for _, q := range qiangbanFilter {
for _, f := range fields {
if strings.ToLower(q) == strings.ToLower(f) {
if strings.EqualFold(q, f) {
return true
}
}

View File

@@ -19,8 +19,8 @@ import (
func (c *Client) addSysCron() {
c.mustAddCron("@every 1m", c.checkTasks)
c.mustAddCron("0 0 * * * *", func() {
c.downloadTvSeries()
c.downloadMovie()
c.downloadAllTvSeries()
c.downloadAllMovies()
})
c.mustAddCron("0 0 */12 * * *", c.checkAllSeriesNewSeason)
c.cron.Start()
@@ -206,79 +206,97 @@ type Task struct {
pkg.Torrent
}
func (c *Client) downloadTvSeries() {
func (c *Client) DownloadSeriesAllEpisodes(id int) ([]string, error) {
tvDetail := c.db.GetMediaDetails(id)
m := make(map[int][]*ent.Episode)
for _, ep := range tvDetail.Episodes {
m[ep.SeasonNumber] = append(m[ep.SeasonNumber], ep)
}
var allNames []string
for seasonNum, epsides := range m {
wantedSeasonPack := true
for _, ep := range epsides {
if !ep.Monitored {
wantedSeasonPack = false
}
if ep.Status != episode.StatusMissing {
wantedSeasonPack = false
}
}
if wantedSeasonPack {
name, err := c.SearchAndDownload(id, seasonNum, -1)
if err != nil {
return nil, errors.Wrap(err, "find resource")
} else {
allNames = append(allNames, *name)
log.Infof("begin download torrent resource: %v", name)
}
} else {
for _, ep := range epsides {
if !ep.Monitored {
continue
}
if ep.Status != episode.StatusMissing {
continue
}
name, err := c.SearchAndDownload(id, ep.SeasonNumber, ep.EpisodeNumber)
if err != nil {
return nil, errors.Wrap(err, "find resource to download")
} else {
allNames = append(allNames, *name)
log.Infof("begin download torrent resource: %v", name)
}
}
}
}
return allNames, nil
}
func (c *Client) downloadAllTvSeries() {
log.Infof("begin check all tv series resources")
allSeries := c.db.GetMediaWatchlist(media.MediaTypeTv)
for _, series := range allSeries {
tvDetail := c.db.GetMediaDetails(series.ID)
m := make(map[int][]*ent.Episode)
for _, ep := range tvDetail.Episodes {
m[ep.SeasonNumber] = append(m[ep.SeasonNumber], ep)
}
for seasonNum, epsides := range m {
wantedSeasonPack := true
for _, ep := range epsides {
if !ep.Monitored {
wantedSeasonPack = false
}
if ep.Status != episode.StatusMissing {
wantedSeasonPack = false
}
}
if wantedSeasonPack {
name, err := c.SearchAndDownload(series.ID, seasonNum, -1)
if err != nil {
log.Infof("cannot find resource to download : %v", err)
} else {
log.Infof("begin download torrent resource: %v", name)
}
} else {
for _, ep := range epsides {
if !ep.Monitored {
continue
}
if ep.Status != episode.StatusMissing {
continue
}
name, err := c.SearchAndDownload(series.ID, ep.SeasonNumber, ep.EpisodeNumber)
if err != nil {
log.Infof("cannot find resource to download for %s: %v", ep.Title, err)
} else {
log.Infof("begin download torrent resource: %v", name)
}
}
}
if _, err := c.DownloadSeriesAllEpisodes(series.ID); err != nil {
return
}
}
}
func (c *Client) downloadMovie() {
func (c *Client) downloadAllMovies() {
log.Infof("begin check all movie resources")
allSeries := c.db.GetMediaWatchlist(media.MediaTypeMovie)
for _, series := range allSeries {
detail := c.db.GetMediaDetails(series.ID)
if len(detail.Episodes) == 0 {
log.Errorf("no related dummy episode: %v", detail.NameEn)
continue
}
ep := detail.Episodes[0]
if ep.Status != episode.StatusMissing {
continue
}
if err := c.downloadMovieSingleEpisode(ep, series.TargetDir); err != nil {
if _, err := c.DownloadMovieByID(series.ID); err != nil {
log.Errorf("download movie error: %v", err)
}
}
}
func (c *Client) downloadMovieSingleEpisode(ep *ent.Episode, targetDir string) error {
func (c *Client) DownloadMovieByID(id int) (string, error) {
detail := c.db.GetMediaDetails(id)
if len(detail.Episodes) == 0 {
return "", fmt.Errorf("no related dummy episode: %v", detail.NameEn)
}
ep := detail.Episodes[0]
if ep.Status != episode.StatusMissing {
return "", nil
}
if name, err := c.downloadMovieSingleEpisode(ep, detail.TargetDir); 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")
return "", errors.Wrap(err, "connect transmission")
}
qiangban := c.db.GetSetting(db.SettingAllowQiangban)
allowQiangban := false
@@ -294,13 +312,13 @@ func (c *Client) downloadMovieSingleEpisode(ep *ent.Episode, targetDir string) e
})
if err != nil {
return errors.Wrap(err, "search movie")
return "", errors.Wrap(err, "search movie")
}
r1 := res[0]
log.Infof("begin download torrent resource: %v", r1.Name)
torrent, err := trc.Download(r1.Link, c.db.GetDownloadDir())
if err != nil {
return errors.Wrap(err, "downloading")
return "", errors.Wrap(err, "downloading")
}
torrent.Start()
@@ -322,7 +340,7 @@ func (c *Client) downloadMovieSingleEpisode(ep *ent.Episode, targetDir string) e
c.tasks[history.ID] = &Task{Torrent: torrent}
c.db.SetEpisodeStatus(ep.ID, episode.StatusDownloading)
return nil
return r1.Name, nil
}
func (c *Client) checkAllSeriesNewSeason() {

View File

@@ -7,6 +7,7 @@ import (
"polaris/log"
"polaris/pkg/torznab"
"polaris/server/core"
"strconv"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
@@ -167,3 +168,21 @@ func (s *Server) DownloadTorrent(c *gin.Context) (interface{}, error) {
}
}
func (s *Server) DownloadAll(c *gin.Context) (interface{}, error) {
ids := c.Param("id")
id, err := strconv.Atoi(ids)
if err != nil {
return nil, errors.Wrap(err, "convert")
}
m, err := s.db.GetMedia(id)
if err != nil {
return nil, errors.Wrap(err, "get media")
}
if m.MediaType == media.MediaTypeTv {
return s.core.DownloadSeriesAllEpisodes(m.ID)
}
name, err := s.core.DownloadMovieByID(m.ID)
return []string{name}, err
}

View File

@@ -91,6 +91,7 @@ func (s *Server) Serve() error {
tv.DELETE("/record/:id", HttpHandler(s.DeleteFromWatchlist))
tv.GET("/suggest/tv/:tmdb_id", HttpHandler(s.SuggestedSeriesFolderName))
tv.GET("/suggest/movie/:tmdb_id", HttpHandler(s.SuggestedMovieFolderName))
tv.GET("/downloadall/:id", HttpHandler(s.DownloadAll))
}
indexer := api.Group("/indexer")
{

View File

@@ -8,6 +8,7 @@ class APIs {
static final _baseUrl = baseUrl();
static final searchUrl = "$_baseUrl/api/v1/media/search";
static final editMediaUrl = "$_baseUrl/api/v1/media/edit";
static final downloadAllUrl = "$_baseUrl/api/v1/media/downloadall/";
static final settingsUrl = "$_baseUrl/api/v1/setting/do";
static final settingsGeneralUrl = "$_baseUrl/api/v1/setting/general";
static final watchlistTvUrl = "$_baseUrl/api/v1/media/tv/watchlist";

View File

@@ -81,6 +81,16 @@ class SeriesDetailData
}
ref.invalidateSelf();
}
Future<void> downloadall() async {
final dio = APIs.getDio();
var resp = await dio.get(APIs.downloadAllUrl + id!);
var sp = ServerResponse.fromJson(resp.data);
if (sp.code != 0) {
throw sp.message;
}
ref.invalidateSelf();
}
}
class SeriesDetails {

View File

@@ -303,9 +303,13 @@ class _DetailCardState extends ConsumerState<DetailCard> {
}
Widget downloadButton() {
return IconButton(
return LoadingIconButton(
tooltip: widget.details.mediaType == "tv" ? "查找并下载所有监控剧集" : "查找并下载此电影",
onPressed: () {},
icon: const Icon(Icons.download_rounded));
onPressed: () async{
await ref
.read(mediaDetailsProvider(widget.details.id.toString()).notifier)
.downloadall();
},
icon: Icons.download_rounded);
}
}