mirror of
https://github.com/simon-ding/polaris.git
synced 2026-02-06 15:10:49 +08:00
feat: download per media feature
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
{
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user