mirror of
https://github.com/simon-ding/polaris.git
synced 2026-04-21 19:27:30 +08:00
code refactor and add season pack size limit
This commit is contained in:
@@ -81,7 +81,13 @@ func (c *Client) DownloadEpisodeTorrent(r1 torznab.Result, seriesId, seasonNum,
|
|||||||
}
|
}
|
||||||
func (c *Client) SearchAndDownload(seriesId, seasonNum, episodeNum int) (*string, error) {
|
func (c *Client) SearchAndDownload(seriesId, seasonNum, episodeNum int) (*string, error) {
|
||||||
|
|
||||||
res, err := SearchTvSeries(c.db, seriesId, seasonNum, []int{episodeNum}, true, true)
|
res, err := SearchTvSeries(c.db, &SearchParam{
|
||||||
|
MediaId: seriesId,
|
||||||
|
SeasonNum: seasonNum,
|
||||||
|
Episodes: []int{episodeNum},
|
||||||
|
CheckFileSize: true,
|
||||||
|
CheckResolution: true,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -254,7 +254,11 @@ func (c *Client) downloadMovieSingleEpisode(ep *ent.Episode) error {
|
|||||||
return errors.Wrap(err, "connect transmission")
|
return errors.Wrap(err, "connect transmission")
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := SearchMovie(c.db, ep.MediaID, true, true)
|
res, err := SearchMovie(c.db, &SearchParam{
|
||||||
|
MediaId: ep.MediaID,
|
||||||
|
CheckFileSize: true,
|
||||||
|
CheckResolution: true,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
||||||
return errors.Wrap(err, "search movie")
|
return errors.Wrap(err, "search movie")
|
||||||
|
|||||||
@@ -3,10 +3,11 @@ package core
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"polaris/db"
|
"polaris/db"
|
||||||
|
"polaris/ent/media"
|
||||||
"polaris/log"
|
"polaris/log"
|
||||||
"polaris/pkg/metadata"
|
"polaris/pkg/metadata"
|
||||||
"polaris/pkg/torznab"
|
"polaris/pkg/torznab"
|
||||||
"polaris/pkg/utils"
|
"regexp"
|
||||||
"slices"
|
"slices"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -16,12 +17,20 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func SearchTvSeries(db1 *db.Client, seriesId, seasonNum int, episodes []int, checkResolution bool, checkFileSize bool) ([]torznab.Result, error) {
|
type SearchParam struct {
|
||||||
series := db1.GetMediaDetails(seriesId)
|
MediaId int
|
||||||
|
SeasonNum int //for tv
|
||||||
|
Episodes []int //for tv
|
||||||
|
CheckResolution bool
|
||||||
|
CheckFileSize bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func SearchTvSeries(db1 *db.Client, param *SearchParam) ([]torznab.Result, error) {
|
||||||
|
series := db1.GetMediaDetails(param.MediaId)
|
||||||
if series == nil {
|
if series == nil {
|
||||||
return nil, fmt.Errorf("no tv series of id %v", seriesId)
|
return nil, fmt.Errorf("no tv series of id %v", param.MediaId)
|
||||||
}
|
}
|
||||||
log.Debugf("check tv series %s, season %d, episode %v", series.NameEn, seasonNum, episodes)
|
log.Debugf("check tv series %s, season %d, episode %v", series.NameEn, param.SeasonNum, param.Episodes)
|
||||||
|
|
||||||
res := searchWithTorznab(db1, series.NameEn, series.NameCn, series.OriginalName)
|
res := searchWithTorznab(db1, series.NameEn, series.NameCn, series.OriginalName)
|
||||||
|
|
||||||
@@ -32,39 +41,32 @@ func SearchTvSeries(db1 *db.Client, seriesId, seasonNum int, episodes []int, che
|
|||||||
if meta == nil { //cannot parse name
|
if meta == nil { //cannot parse name
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !isNumberedSeries(series) && meta.Season != seasonNum { //do not check season on series that only rely on episode number
|
if !isNoSeasonSeries(series) && meta.Season != param.SeasonNum { //do not check season on series that only rely on episode number
|
||||||
continue
|
continue
|
||||||
|
|
||||||
}
|
}
|
||||||
if isNumberedSeries(series) && len(episodes) == 0 {
|
if isNoSeasonSeries(series) && len(param.Episodes) == 0 {
|
||||||
//should not want season
|
//should not want season
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(episodes) > 0 && !slices.Contains(episodes, meta.Episode) { //not season pack, but episode number not equal
|
if len(param.Episodes) > 0 && !slices.Contains(param.Episodes, meta.Episode) { //not season pack, but episode number not equal
|
||||||
continue
|
continue
|
||||||
|
|
||||||
} else if len(episodes) == 0 && !meta.IsSeasonPack { //want season pack, but not season pack
|
} else if len(param.Episodes) == 0 && !meta.IsSeasonPack { //want season pack, but not season pack
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if checkResolution && meta.Resolution != series.Resolution.String() {
|
if param.CheckResolution && meta.Resolution != series.Resolution.String() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !utils.IsNameAcceptable(meta.NameEn, series.NameEn) && !utils.IsNameAcceptable(meta.NameCn, series.NameCn) &&
|
if !torrentNameOk(series, r.Name) {
|
||||||
!utils.IsNameAcceptable(meta.NameCn, series.OriginalName) {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if checkFileSize {
|
if !torrentSizeOk(series, r.Size, param) {
|
||||||
if series.Limiter.SizeMin > 0 && r.Size < series.Limiter.SizeMin {
|
continue
|
||||||
//min size not satified
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if series.Limiter.SizeMax > 0 && r.Size > series.Limiter.SizeMax {
|
|
||||||
//max size not satified
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
filtered = append(filtered, r)
|
filtered = append(filtered, r)
|
||||||
}
|
}
|
||||||
if len(filtered) == 0 {
|
if len(filtered) == 0 {
|
||||||
@@ -75,7 +77,40 @@ func SearchTvSeries(db1 *db.Client, seriesId, seasonNum int, episodes []int, che
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func isNumberedSeries(detail *db.MediaDetails) bool {
|
func torrentSizeOk(detail *db.MediaDetails, torrentSize int, param *SearchParam) bool {
|
||||||
|
if param.CheckFileSize {
|
||||||
|
multiplier := 1 //大小倍数,正常为1,如果是季包则为季内集数
|
||||||
|
if detail.MediaType == media.MediaTypeTv && len(param.Episodes) == 0 { //tv season pack
|
||||||
|
multiplier = seasonEpisodeCount(detail, param.SeasonNum)
|
||||||
|
}
|
||||||
|
|
||||||
|
if detail.Limiter.SizeMin > 0 { //min size
|
||||||
|
sizeMin := detail.Limiter.SizeMin * multiplier
|
||||||
|
if torrentSize < sizeMin { //比最小要求的大小还要小
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if detail.Limiter.SizeMax > 0 { //max size
|
||||||
|
sizeMax := detail.Limiter.SizeMax * multiplier
|
||||||
|
if torrentSize > sizeMax { //larger than max size wanted
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func seasonEpisodeCount(detail *db.MediaDetails, seasonNum int) int {
|
||||||
|
count := 0
|
||||||
|
for _, ep := range detail.Episodes {
|
||||||
|
if ep.SeasonNumber == seasonNum {
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNoSeasonSeries(detail *db.MediaDetails) bool {
|
||||||
hasSeason2 := false
|
hasSeason2 := false
|
||||||
season2HasEpisode1 := false
|
season2HasEpisode1 := false
|
||||||
for _, ep := range detail.Episodes {
|
for _, ep := range detail.Episodes {
|
||||||
@@ -90,8 +125,8 @@ func isNumberedSeries(detail *db.MediaDetails) bool {
|
|||||||
return hasSeason2 && !season2HasEpisode1 //only one 1st episode
|
return hasSeason2 && !season2HasEpisode1 //only one 1st episode
|
||||||
}
|
}
|
||||||
|
|
||||||
func SearchMovie(db1 *db.Client, movieId int, checkResolution bool, checkFileSize bool) ([]torznab.Result, error) {
|
func SearchMovie(db1 *db.Client, param *SearchParam) ([]torznab.Result, error) {
|
||||||
movieDetail := db1.GetMediaDetails(movieId)
|
movieDetail := db1.GetMediaDetails(param.MediaId)
|
||||||
if movieDetail == nil {
|
if movieDetail == nil {
|
||||||
return nil, errors.New("no media found of id")
|
return nil, errors.New("no media found of id")
|
||||||
}
|
}
|
||||||
@@ -104,23 +139,16 @@ func SearchMovie(db1 *db.Client, movieId int, checkResolution bool, checkFileSiz
|
|||||||
var filtered []torznab.Result
|
var filtered []torznab.Result
|
||||||
for _, r := range res {
|
for _, r := range res {
|
||||||
meta := metadata.ParseMovie(r.Name)
|
meta := metadata.ParseMovie(r.Name)
|
||||||
if !utils.IsNameAcceptable(meta.Name, movieDetail.NameEn) && !utils.IsNameAcceptable(meta.Name, movieDetail.NameCn) &&
|
if !torrentNameOk(movieDetail, r.Name) {
|
||||||
!utils.IsNameAcceptable(meta.Name, movieDetail.OriginalName) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if checkResolution && meta.Resolution != movieDetail.Resolution.String() {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if checkFileSize {
|
if param.CheckResolution && meta.Resolution != movieDetail.Resolution.String() {
|
||||||
if movieDetail.Limiter.SizeMin > 0 && r.Size < movieDetail.Limiter.SizeMin {
|
continue
|
||||||
//min size not satified
|
}
|
||||||
continue
|
|
||||||
}
|
if !torrentSizeOk(movieDetail, r.Size, param) {
|
||||||
if movieDetail.Limiter.SizeMax > 0 && r.Size > movieDetail.Limiter.SizeMax {
|
continue
|
||||||
//max size not satified
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ss := strings.Split(movieDetail.AirDate, "-")[0]
|
ss := strings.Split(movieDetail.AirDate, "-")[0]
|
||||||
@@ -176,7 +204,7 @@ func searchWithTorznab(db *db.Client, queries ...string) []torznab.Result {
|
|||||||
res = append(res, result...)
|
res = append(res, result...)
|
||||||
}
|
}
|
||||||
|
|
||||||
//res = dedup(res)
|
res = dedup(res)
|
||||||
|
|
||||||
sort.SliceStable(res, func(i, j int) bool { //先按做种人数排序
|
sort.SliceStable(res, func(i, j int) bool { //先按做种人数排序
|
||||||
var s1 = res[i]
|
var s1 = res[i]
|
||||||
@@ -226,3 +254,17 @@ func dedup(list []torznab.Result) []torznab.Result {
|
|||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func torrentNameOk(detail *db.MediaDetails, torrentName string) bool {
|
||||||
|
return isNameAcceptable(torrentName, detail.NameCn) || isNameAcceptable(torrentName, detail.NameEn) ||
|
||||||
|
isNameAcceptable(torrentName, detail.OriginalName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNameAcceptable(torrentName, wantedName string) bool {
|
||||||
|
re := regexp.MustCompile(`[^\p{L}\w\s]`)
|
||||||
|
torrentName = re.ReplaceAllString(strings.ToLower(torrentName), " ")
|
||||||
|
wantedName = re.ReplaceAllString(strings.ToLower(wantedName), " ")
|
||||||
|
torrentName = strings.Join(strings.Fields(torrentName), " ")
|
||||||
|
wantedName = strings.Join(strings.Fields(wantedName), " ")
|
||||||
|
return strings.Contains(torrentName, wantedName)
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,7 +13,13 @@ import (
|
|||||||
|
|
||||||
func (s *Server) searchAndDownloadSeasonPackage(seriesId, seasonNum int) (*string, error) {
|
func (s *Server) searchAndDownloadSeasonPackage(seriesId, seasonNum int) (*string, error) {
|
||||||
|
|
||||||
res, err := core.SearchTvSeries(s.db, seriesId, seasonNum, nil, true, true)
|
res, err := core.SearchTvSeries(s.db, &core.SearchParam{
|
||||||
|
MediaId: seriesId,
|
||||||
|
SeasonNum: seasonNum,
|
||||||
|
Episodes: nil,
|
||||||
|
CheckResolution: true,
|
||||||
|
CheckFileSize: true,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -46,13 +52,21 @@ func (s *Server) SearchAvailableTorrents(c *gin.Context) (interface{}, error) {
|
|||||||
if in.Episode == 0 {
|
if in.Episode == 0 {
|
||||||
//search season package
|
//search season package
|
||||||
log.Infof("search series season package S%02d", in.Season)
|
log.Infof("search series season package S%02d", in.Season)
|
||||||
res, err = core.SearchTvSeries(s.db, in.ID, in.Season, nil, false, false)
|
res, err = core.SearchTvSeries(s.db, &core.SearchParam{
|
||||||
|
MediaId: in.ID,
|
||||||
|
SeasonNum: in.Season,
|
||||||
|
Episodes: nil,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "search season package")
|
return nil, errors.Wrap(err, "search season package")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Infof("search series episode S%02dE%02d", in.Season, in.Episode)
|
log.Infof("search series episode S%02dE%02d", in.Season, in.Episode)
|
||||||
res, err = core.SearchTvSeries(s.db, in.ID, in.Season, []int{in.Episode}, false, false)
|
res, err = core.SearchTvSeries(s.db, &core.SearchParam{
|
||||||
|
MediaId: in.ID,
|
||||||
|
SeasonNum: in.Season,
|
||||||
|
Episodes: []int{in.Episode},
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err.Error() == "no resource found" {
|
if err.Error() == "no resource found" {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
@@ -63,7 +77,9 @@ func (s *Server) SearchAvailableTorrents(c *gin.Context) (interface{}, error) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Info("search movie %d", in.ID)
|
log.Info("search movie %d", in.ID)
|
||||||
res, err = core.SearchMovie(s.db, in.ID, false, false)
|
res, err = core.SearchMovie(s.db, &core.SearchParam{
|
||||||
|
MediaId: in.ID,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err.Error() == "no resource found" {
|
if err.Error() == "no resource found" {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
|
|||||||
@@ -114,7 +114,8 @@ class _DetailCardState extends ConsumerState<DetailCard> {
|
|||||||
"${(widget.details.limiter!.sizeMin).readableFileSize()} - ${(widget.details.limiter!.sizeMax).readableFileSize()}"))
|
"${(widget.details.limiter!.sizeMin).readableFileSize()} - ${(widget.details.limiter!.sizeMax).readableFileSize()}"))
|
||||||
: const SizedBox(),
|
: const SizedBox(),
|
||||||
MenuAnchor(
|
MenuAnchor(
|
||||||
style: MenuStyle(alignment: Alignment.bottomRight),
|
style:
|
||||||
|
MenuStyle(alignment: Alignment.bottomRight),
|
||||||
menuChildren: [
|
menuChildren: [
|
||||||
ActionChip.elevated(
|
ActionChip.elevated(
|
||||||
onPressed: () => launchUrl(url),
|
onPressed: () => launchUrl(url),
|
||||||
|
|||||||
Reference in New Issue
Block a user