feat: match tv release year

This commit is contained in:
Simon Ding
2025-04-28 14:31:46 +08:00
parent b81c5d327c
commit c58a038daf
4 changed files with 95 additions and 15 deletions

View File

@@ -13,6 +13,7 @@ import (
"strconv"
"strings"
"sync"
"time"
"github.com/pkg/errors"
)
@@ -71,6 +72,26 @@ func names2Query(media *ent.Media) []string {
return names
}
func getSeasonReleaseYear(series *db.MediaDetails, seasonNum int) int {
if seasonNum == 0 {
return 0
}
releaseYear := 0
for _, s := range series.Episodes {
if s.SeasonNumber == seasonNum && s.AirDate != "" {
ss := strings.Split(s.AirDate, "-")[0]
y, err := strconv.Atoi(ss)
if err != nil {
continue
}
releaseYear = y
break
}
}
return releaseYear
}
func SearchTvSeries(db1 db.Database, param *SearchParam) ([]torznab.Result, error) {
series, err := db1.GetMediaDetails(param.MediaId)
if err != nil {
@@ -87,6 +108,11 @@ func SearchTvSeries(db1 db.Database, param *SearchParam) ([]torznab.Result, erro
res := searchWithTorznab(db1, SearchTypeTv, names...)
ss := strings.Split(series.AirDate, "-")[0]
releaseYear, _ := strconv.Atoi(ss)
seasonYear := getSeasonReleaseYear(series, param.SeasonNum)
var filtered []torznab.Result
lo:
for _, r := range res {
@@ -102,6 +128,17 @@ lo:
if !torrentNameOk(series, meta) {
continue
}
if meta.Year > 0 && releaseYear > 0 {
if meta.Year != releaseYear && meta.Year != releaseYear-1 && meta.Year != releaseYear+1 { //year not match
if seasonYear > 0 { // if tv release year is not match, check season release year
if meta.Year != seasonYear && meta.Year != seasonYear-1 && meta.Year != seasonYear+1 { //season year not match
continue lo
}
} else {
continue lo
}
}
}
}
if !isNoSeasonSeries(series) && meta.Season != param.SeasonNum { //do not check season on series that only rely on episode number
@@ -311,6 +348,10 @@ const (
)
func searchWithTorznab(db db.Database, t SearchType, queries ...string) []torznab.Result {
t1 := time.Now()
defer func() {
log.Infof("search with torznab took %v", time.Since(t1))
}()
var res []torznab.Result
allTorznab := db.GetAllIndexers()

View File

@@ -34,33 +34,56 @@ func (m *MovieMetadata) IsAcceptable(names... string) bool {
return false
}
func ParseMovie(name string) *MovieMetadata {
name = strings.Join(strings.Fields(name), " ") //remove unnessary spaces
name = strings.ToLower(strings.TrimSpace(name))
var meta = &MovieMetadata{}
func findYear(name string) (year int, index int) {
yearRe := regexp.MustCompile(`\(\d{4}\)`)
yearMatches := yearRe.FindAllString(name, -1)
var yearIndex = -1
index = -1
if len(yearMatches) > 0 {
yearIndex = strings.Index(name, yearMatches[0])
index = strings.Index(name, yearMatches[0])
y := yearMatches[0][1 : len(yearMatches[0])-1]
n, err := strconv.Atoi(y)
if err != nil {
panic(fmt.Sprintf("convert %s error: %v", y, err))
}
meta.Year = n
year = n
} else {
yearRe := regexp.MustCompile(`\d{4}`)
yearMatches := yearRe.FindAllString(name, -1)
if len(yearMatches) > 0 {
n, err := strconv.Atoi(yearMatches[0])
if err != nil {
panic(fmt.Sprintf("convert %s error: %v", yearMatches[0], err))
}
meta.Year = n
year, index = findYearInMatches(yearMatches, name)
}
}
return
}
func findYearInMatches(matches []string, name string) (year int, index int) {
if len(matches) == 0 {
return 0, -1
}
for _, y := range matches {
index = strings.Index(name, y)
n, err := strconv.Atoi(y)
if err != nil {
panic(fmt.Sprintf("convert %s error: %v", y, err))
}
if n < 1900 || n > 2050 {
continue
}
year = n
}
return
}
func ParseMovie(name string) *MovieMetadata {
name = strings.Join(strings.Fields(name), " ") //remove unnessary spaces
name = strings.ToLower(strings.TrimSpace(name))
var meta = &MovieMetadata{}
year, yearIndex := findYear(name)
meta.Year = year
if yearIndex != -1 {
meta.Name = name[:yearIndex]

View File

@@ -272,7 +272,7 @@ func matchResolution(s string) string {
func maybeSeasonPack(s string) bool {
//season pack
packRe := regexp.MustCompile(`((\d{1,2}-\d{1,2}))|(complete)|(全集)|(\W[sS]\d{1,2}\W)`)
packRe := regexp.MustCompile(`((\d{1,2}-\d{1,2}))|(complete)|(全集)|(合集)|(\W[sS]\d{1,2}\W)`)
if packRe.MatchString(s) {
return true
}
@@ -409,6 +409,8 @@ func parseName(name string) *Info {
if strings.TrimSpace(name) == "" {
return meta
}
year, yearP := findYear(name)
meta.Year = year
season, p := findSeason(name)
if season == -1 {
@@ -437,7 +439,11 @@ func parseName(name string) *Info {
//tv name
if utils.IsASCII(name) && p < len(name) && p-1 > 0 {
meta.NameEn = strings.TrimSpace(name[:p-1])
p1 := p -1
if yearP > 0 {
p1 = min(p1, yearP-1)
}
meta.NameEn = strings.TrimSpace(name[:p1])
meta.NameCn = meta.NameEn
} else {
fields := strings.FieldsFunc(name, func(r rune) bool {

View File

@@ -206,6 +206,16 @@ func Test_ParseTV20(t *testing.T) {
assert.Equal(t, true, m.IsSeasonPack)
}
func Test_ParseTV21(t *testing.T) {
s1 := "【东京不够热】基督山伯爵-华丽的复仇-【01~09】【1280x720】【简中/日双语字幕】【2018春季日剧】【合集】 "
m := ParseTv(s1)
log.Infof("results: %+v", m)
assert.Equal(t, 1, m.Season)
assert.Equal(t, 2018, m.Year)
assert.Equal(t, true, m.IsSeasonPack)
}
// The Day of the Jackal (Season 1) WEB-DL 1080p
func Test_ParseTV19(t *testing.T) {
s1 := "The Day of the Jackal (Season 1) WEB-DL 1080p "