mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-01 03:56:38 +08:00
fix: improve discover and manual scrape flows
This commit is contained in:
@@ -399,8 +399,8 @@ func (s *ScraperService) manualDoubanMatch(ctx context.Context, query string) *M
|
||||
if s.douban == nil || !s.douban.Enabled() {
|
||||
return nil
|
||||
}
|
||||
if _, ok := parsePositiveInt(query); ok {
|
||||
if match, err := s.douban.GetMatchByID(ctx, query); err == nil && match != nil {
|
||||
if id, ok := parsePositiveIDString(query); ok {
|
||||
if match, err := s.douban.GetMatchByID(ctx, id); err == nil && match != nil {
|
||||
return match
|
||||
}
|
||||
}
|
||||
@@ -431,8 +431,8 @@ func (s *ScraperService) manualTheTVDBMatch(ctx context.Context, query string) *
|
||||
if s.thetvdb == nil || !s.thetvdb.Enabled() {
|
||||
return nil
|
||||
}
|
||||
if _, ok := parsePositiveInt(normalizeTheTVDBSeriesID(query)); ok {
|
||||
if match, err := s.thetvdb.GetSeriesMatchByID(ctx, query); err == nil && match != nil {
|
||||
if id, ok := parsePositiveIDString(normalizeTheTVDBSeriesID(query)); ok {
|
||||
if match, err := s.thetvdb.GetSeriesMatchByID(ctx, id); err == nil && match != nil {
|
||||
return match
|
||||
}
|
||||
}
|
||||
@@ -508,6 +508,14 @@ func parsePositiveInt(value string) (int, bool) {
|
||||
return id, err == nil && id > 0
|
||||
}
|
||||
|
||||
func parsePositiveIDString(value string) (string, bool) {
|
||||
id, ok := parsePositiveInt(value)
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
return strconv.Itoa(id), true
|
||||
}
|
||||
|
||||
func manualScrapeBatchName(ids []string) string {
|
||||
if len(ids) == 1 {
|
||||
return ids[0]
|
||||
|
||||
@@ -32,6 +32,24 @@ func TestManualRequestMatchFallsBackToCandidatePayload(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePositiveIDStringAcceptsProviderPrefixes(t *testing.T) {
|
||||
cases := map[string]string{
|
||||
"12345": "12345",
|
||||
"tmdb:12345": "12345",
|
||||
"douban:67890": "67890",
|
||||
"thetvdb:24680": "24680",
|
||||
}
|
||||
for input, want := range cases {
|
||||
got, ok := parsePositiveIDString(input)
|
||||
if !ok || got != want {
|
||||
t.Fatalf("parsePositiveIDString(%q) = %q,%v; want %q,true", input, got, ok, want)
|
||||
}
|
||||
}
|
||||
if got, ok := parsePositiveIDString("tmdb:not-a-number"); ok || got != "" {
|
||||
t.Fatalf("parsePositiveIDString invalid = %q,%v; want empty,false", got, ok)
|
||||
}
|
||||
}
|
||||
|
||||
func TestManualSearchReturnsTMDbCandidatePage(t *testing.T) {
|
||||
upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
@@ -169,10 +169,11 @@ func compactSeriesKey(raw string) string {
|
||||
}
|
||||
|
||||
var (
|
||||
seriesYearRE = regexp.MustCompile(`\s*\((?:19|20)\d{2}\)\s*`)
|
||||
seriesIDRE = regexp.MustCompile(`(?i)\s*\[(?:tmdb|tmdbid)[=-]\d+\]\s*`)
|
||||
seriesBraceRE = regexp.MustCompile(`(?i)\s*\{(?:tmdb|tmdbid|douban|bangumi|bgm|thetvdb|tvdb)[\s:=#-]*[a-z0-9_-]+\}\s*`)
|
||||
seriesSpacerRE = regexp.MustCompile(`[\s._-]+`)
|
||||
seriesYearRE = regexp.MustCompile(`\s*\((?:19|20)\d{2}\)\s*`)
|
||||
seriesIDRE = regexp.MustCompile(`(?i)\s*\[(?:tmdb|tmdbid)[=-]\d+\]\s*`)
|
||||
seriesBraceRE = regexp.MustCompile(`(?i)\s*\{(?:tmdb|tmdbid|douban|bangumi|bgm|thetvdb|tvdb)[\s:=#-]*[a-z0-9_-]+\}\s*`)
|
||||
seriesSpacerRE = regexp.MustCompile(`[\s._-]+`)
|
||||
seriesSpecialSuffixRE = regexp.MustCompile(`(?i)(?:\s+(?:specials?|sp|ova|oad|extra|extras)|\s*(?:特别篇|特別篇|番外|特典|外传|外傳))$`)
|
||||
)
|
||||
|
||||
func normalizeSeriesTitle(value string) string {
|
||||
@@ -184,6 +185,15 @@ func normalizeSeriesTitle(value string) string {
|
||||
return strings.TrimSpace(value)
|
||||
}
|
||||
|
||||
func normalizeSeriesPathTitle(value string) string {
|
||||
title := normalizeSeriesTitle(value)
|
||||
stripped := strings.TrimSpace(seriesSpecialSuffixRE.ReplaceAllString(title, ""))
|
||||
if stripped != "" {
|
||||
return stripped
|
||||
}
|
||||
return title
|
||||
}
|
||||
|
||||
func seriesTitleFromMediaPath(path string) string {
|
||||
if strings.TrimSpace(path) == "" {
|
||||
return ""
|
||||
@@ -199,7 +209,7 @@ func seriesTitleFromMediaPath(path string) string {
|
||||
if dirIndex < 0 {
|
||||
return ""
|
||||
}
|
||||
return normalizeSeriesTitle(parts[dirIndex])
|
||||
return normalizeSeriesPathTitle(parts[dirIndex])
|
||||
}
|
||||
|
||||
func seriesDisplayTitle(media model.Media) string {
|
||||
|
||||
@@ -27,3 +27,37 @@ func TestMediaSeriesKeyCollapsesNestedSpecialFolders(t *testing.T) {
|
||||
t.Fatalf("cards=%#v, want one merged series card with two items", cards)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMediaSeriesKeyCollapsesSpecialTitleSuffix(t *testing.T) {
|
||||
main := model.Media{
|
||||
LibraryID: "lib-tv",
|
||||
Path: `cloud://openlist/电视剧/欧美剧/Example Show/Season 01/Example.Show.S01E01.mkv`,
|
||||
SeasonNum: 1,
|
||||
EpisodeNum: 1,
|
||||
}
|
||||
special := model.Media{
|
||||
LibraryID: "lib-tv",
|
||||
Path: `cloud://openlist/电视剧/欧美剧/Example Show Specials/Example.Show.Special.01.mkv`,
|
||||
SeasonNum: 0,
|
||||
EpisodeNum: 1,
|
||||
}
|
||||
chineseSpecial := model.Media{
|
||||
LibraryID: "lib-tv",
|
||||
Path: `cloud://openlist/动漫/国漫/示例剧 特别篇/示例剧.SP01.mkv`,
|
||||
SeasonNum: 0,
|
||||
EpisodeNum: 1,
|
||||
}
|
||||
chineseMain := model.Media{
|
||||
LibraryID: "lib-tv",
|
||||
Path: `cloud://openlist/动漫/国漫/示例剧/Season 01/示例剧.S01E01.mkv`,
|
||||
SeasonNum: 1,
|
||||
EpisodeNum: 1,
|
||||
}
|
||||
|
||||
if got, want := mediaSeriesKey(special), mediaSeriesKey(main); got != want {
|
||||
t.Fatalf("english special key=%q, want main key=%q", got, want)
|
||||
}
|
||||
if got, want := mediaSeriesKey(chineseSpecial), mediaSeriesKey(chineseMain); got != want {
|
||||
t.Fatalf("chinese special key=%q, want main key=%q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user