Skip to content

Commit ae324ab

Browse files
committed
feat: enhance regex patterns for title cleaning and season number inference; add benchmarks for performance testing
1 parent 4e3e924 commit ae324ab

12 files changed

Lines changed: 170 additions & 68 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,6 @@ build/goanime-local
2929
#claude
3030
claude
3131
.claude
32+
33+
# folder .tokensave
34+
.tokensave/

internal/api/anime.go

Lines changed: 59 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -466,13 +466,11 @@ func generateSearchVariations(cleanedName string) []string {
466466
}
467467

468468
// Variation: Remove trailing roman numerals (seasons like II, III, IV)
469-
reRoman := regexp.MustCompile(`\s+(?:II|III|IV|V|VI|VII|VIII|IX|X)\s*$`)
470469
if match := reRoman.FindString(cleanedName); match != "" {
471470
addVariation(strings.TrimSpace(reRoman.ReplaceAllString(cleanedName, "")))
472471
}
473472

474473
// Variation: Remove trailing numbers that might be season indicators (2, 3, 4, etc.)
475-
reTrailingNum := regexp.MustCompile(`\s+\d+\s*$`)
476474
if match := reTrailingNum.FindString(cleanedName); match != "" {
477475
addVariation(strings.TrimSpace(reTrailingNum.ReplaceAllString(cleanedName, "")))
478476
}
@@ -491,7 +489,6 @@ func generateSearchVariations(cleanedName string) []string {
491489

492490
// Variation: Remove common PT-BR descriptive suffixes (Clássico, Classic, etc.)
493491
// These are used by Brazilian sites to distinguish series (e.g. "Naruto Clássico" vs "Naruto Shippuden")
494-
rePtBRSuffix := regexp.MustCompile(`(?i)\s+(?:cl[aá]ssico|classic|shippuuden|next\s+generations?)\s*$`)
495492
if rePtBRSuffix.MatchString(cleanedName) {
496493
addVariation(strings.TrimSpace(rePtBRSuffix.ReplaceAllString(cleanedName, "")))
497494
}
@@ -515,96 +512,110 @@ func generateSearchVariations(cleanedName string) []string {
515512
return variations
516513
}
517514

515+
// Compiled once at init: CleanTitle and generateSearchVariations run per search
516+
// result, so recompiling these on every call dominated the search hot path.
517+
var (
518+
// generateSearchVariations patterns
519+
reRoman = regexp.MustCompile(`\s+(?:II|III|IV|V|VI|VII|VIII|IX|X)\s*$`)
520+
reTrailingNum = regexp.MustCompile(`\s+\d+\s*$`)
521+
rePtBRSuffix = regexp.MustCompile(`(?i)\s+(?:cl[aá]ssico|classic|shippuuden|next\s+generations?)\s*$`)
522+
523+
// CleanTitle patterns, applied in order
524+
reMediaTags = regexp.MustCompile(`^\s*\[(?:Movies?(?:/TV)?|TV|Anime|Series|Show)\]\s*`)
525+
reLangTags = regexp.MustCompile(`^\s*\[(?:English|PT-BR|Portuguese|Português|Japonês|Japanese|Multilanguage)\]\s*`)
526+
reSourceTag = regexp.MustCompile(`(?i)[🔥🌐]?\[(?:animefire|allanime|animedrive|9anime)\]\s*`)
527+
reEmDash = regexp.MustCompile(`\s*[–—]\s+.*$`)
528+
// For the regular hyphen ( - ) we cannot strip blindly — it appears inside legitimate
529+
// titles such as "Jujutsu Kaisen: Shimetsu Kaiyuu - Zenpen" / "- Kouhen" (前編/後編,
530+
// Part 1 / Part 2 on AniList). Only strip when the suffix matches known PT-BR noise
531+
// or season/episode markers; otherwise keep the dash and what follows so AniList
532+
// resolves the correct entry.
533+
reSpaceDashNoise = regexp.MustCompile(`(?i)\s+-\s+(?:` +
534+
`dublado|legendado|dual\s*[aá]udio|dub|sub|completo|` +
535+
`todos\s+os\s+epis[oó]dios?|` +
536+
`epis[oó]dios?\s*\d+|ep\s*\d+|` +
537+
`\d+[ªº]?\s*temporada|temporada\s*\d*|` +
538+
`season\s*\d+|\d+(?:st|nd|rd|th)\s*season|` +
539+
`parte\s*\d+|part\s*\d+|` +
540+
`allanime|animefire|animedrive|9anime|goyabu|superflix|flixhq|sflix` +
541+
`).*$`)
542+
reLangParens = regexp.MustCompile(`(?i)\s*\([^)]*(?:dublado|legendado|dub|sub)[^)]*\)`)
543+
reLangSuffix = regexp.MustCompile(`(?i)\s+(?:dublado|legendado|dub|sub|dual\s*[aá]udio)\s*$`)
544+
reTodosEps = regexp.MustCompile(`(?i)[-–—]?\s*todos\s+os\s+epis[oó]dios`)
545+
reCompleto = regexp.MustCompile(`(?i)\s+(?:completo|episodio\s*\d+|ep\s*\d+)\s*$`)
546+
reSeasonPt = regexp.MustCompile(`(?i)\s*[-–—]?\s*(?:\d+[ªº]?\s*temporada|temporada\s*\d+|season\s*\d+|\d+(?:st|nd|rd|th)\s*season)\s*$`)
547+
rePart = regexp.MustCompile(`(?i)\s*[-–—]?\s*(?:parte\s*\d+|part\s*\d+)\s*$`)
548+
reSeasonEpTag = regexp.MustCompile(`\s+\d+(\.\d+)?\s+A\d+\s*$`)
549+
reDecimalSuffix = regexp.MustCompile(`\s+\d+\.\d+\s*$`)
550+
reEpCount = regexp.MustCompile(`(?i)\s*\(\d+\s+(?:episodes?|eps?|epis[oó]dios?)\)`)
551+
re9AnimeEpInfo = regexp.MustCompile(`(?i)\s*\((?:HD\s+)?(?:(?:SUB|DUB)\s+)*Ep\s+\d+/\d+\)`)
552+
reSpecialTitles = regexp.MustCompile(`(?i):\s*(?:Jump Festa \d+|The All Magic Knights|Sword of the Wizard King|Mahou Tei no Ken).*$`)
553+
reNASuffix = regexp.MustCompile(`(?i)\s+N/A\s*$`)
554+
reEmptyParens = regexp.MustCompile(`\s*\(\s*\)`)
555+
reHyphenLetters = regexp.MustCompile(`([a-zA-Z])-([a-zA-Z])`)
556+
reWhitespaceRun = regexp.MustCompile(`\s+`)
557+
)
558+
518559
func CleanTitle(title string) string {
519560
cleaned := title
520561

521562
// Remove media type tags like [Movies/TV], [Anime], [Series], [Movie] at the start
522-
reMediaTags := regexp.MustCompile(`^\s*\[(?:Movies?(?:/TV)?|TV|Anime|Series|Show)\]\s*`)
523563
cleaned = strings.TrimSpace(reMediaTags.ReplaceAllString(cleaned, ""))
524564

525565
// Remove language tags like [English], [PT-BR], [Portuguese], [Português], [Multilanguage] at the start
526-
reLangTags := regexp.MustCompile(`^\s*\[(?:English|PT-BR|Portuguese|Português|Japonês|Japanese|Multilanguage)\]\s*`)
527566
cleaned = strings.TrimSpace(reLangTags.ReplaceAllString(cleaned, ""))
528567

529568
// Remove source tags like 🔥[AnimeFire], 🌐[AllAnime], [AnimeDrive], or [9Anime]
530-
re1 := regexp.MustCompile(`(?i)[🔥🌐]?\[(?:animefire|allanime|animedrive|9anime)\]\s*`)
531-
cleaned = strings.TrimSpace(re1.ReplaceAllString(cleaned, ""))
569+
cleaned = strings.TrimSpace(reSourceTag.ReplaceAllString(cleaned, ""))
532570

533571
// Remove everything after em-dash or en-dash (typically subtitles like "– Todos os Episódios").
534572
// Em/en dashes are almost always used as noise separators in PT-BR scrapers.
535-
reEmDash := regexp.MustCompile(`\s*[–—]\s+.*$`)
536573
cleaned = strings.TrimSpace(reEmDash.ReplaceAllString(cleaned, ""))
537574

538-
// For the regular hyphen ( - ) we cannot strip blindly — it appears inside legitimate
539-
// titles such as "Jujutsu Kaisen: Shimetsu Kaiyuu - Zenpen" / "- Kouhen" (前編/後編,
540-
// Part 1 / Part 2 on AniList). Only strip when the suffix matches known PT-BR noise
541-
// or season/episode markers; otherwise keep the dash and what follows so AniList
542-
// resolves the correct entry.
543-
reSpaceDashNoise := regexp.MustCompile(`(?i)\s+-\s+(?:` +
544-
`dublado|legendado|dual\s*[aá]udio|dub|sub|completo|` +
545-
`todos\s+os\s+epis[oó]dios?|` +
546-
`epis[oó]dios?\s*\d+|ep\s*\d+|` +
547-
`\d+[ªº]?\s*temporada|temporada\s*\d*|` +
548-
`season\s*\d+|\d+(?:st|nd|rd|th)\s*season|` +
549-
`parte\s*\d+|part\s*\d+|` +
550-
`allanime|animefire|animedrive|9anime|goyabu|superflix|flixhq|sflix` +
551-
`).*$`)
575+
// Strip " - <noise>" suffixes (see reSpaceDashNoise for why plain hyphens
576+
// can't be stripped blindly).
552577
cleaned = strings.TrimSpace(reSpaceDashNoise.ReplaceAllString(cleaned, ""))
553578

554579
// Remove content in parentheses if it contains language info (do this BEFORE removing standalone language indicators)
555-
re6 := regexp.MustCompile(`(?i)\s*\([^)]*(?:dublado|legendado|dub|sub)[^)]*\)`)
556-
cleaned = strings.TrimSpace(re6.ReplaceAllString(cleaned, ""))
580+
cleaned = strings.TrimSpace(reLangParens.ReplaceAllString(cleaned, ""))
557581

558582
// Remove standalone language indicators (not in parentheses) - more comprehensive for Brazilian sources
559-
re2 := regexp.MustCompile(`(?i)\s+(?:dublado|legendado|dub|sub|dual\s*[aá]udio)\s*$`)
560-
cleaned = strings.TrimSpace(re2.ReplaceAllString(cleaned, ""))
583+
cleaned = strings.TrimSpace(reLangSuffix.ReplaceAllString(cleaned, ""))
561584

562585
// Remove "Todos os Episodios" and similar Brazilian phrases (in case em-dash removal didn't catch it)
563-
re3 := regexp.MustCompile(`(?i)[-–—]?\s*todos\s+os\s+epis[oó]dios`)
564-
cleaned = strings.TrimSpace(re3.ReplaceAllString(cleaned, ""))
586+
cleaned = strings.TrimSpace(reTodosEps.ReplaceAllString(cleaned, ""))
565587

566588
// Remove "Completo" or "Episodio X" suffixes common in Brazilian sources
567-
reCompleto := regexp.MustCompile(`(?i)\s+(?:completo|episodio\s*\d+|ep\s*\d+)\s*$`)
568589
cleaned = strings.TrimSpace(reCompleto.ReplaceAllString(cleaned, ""))
569590

570591
// Remove season indicators like "X Temporada", "Season X", "Temporada X", "Xª Temporada"
571-
reSeasonPt := regexp.MustCompile(`(?i)\s*[-–—]?\s*(?:\d+[ªº]?\s*temporada|temporada\s*\d+|season\s*\d+|\d+(?:st|nd|rd|th)\s*season)\s*$`)
572592
cleaned = strings.TrimSpace(reSeasonPt.ReplaceAllString(cleaned, ""))
573593

574594
// Remove "Parte X" (Part X) common in Brazilian titles
575-
rePart := regexp.MustCompile(`(?i)\s*[-–—]?\s*(?:parte\s*\d+|part\s*\d+)\s*$`)
576595
cleaned = strings.TrimSpace(rePart.ReplaceAllString(cleaned, ""))
577596

578597
// Remove season/episode indicators like "2.0 A2" at the end (but NOT plain season numbers)
579-
re4 := regexp.MustCompile(`\s+\d+(\.\d+)?\s+A\d+\s*$`)
580-
cleaned = strings.TrimSpace(re4.ReplaceAllString(cleaned, ""))
598+
cleaned = strings.TrimSpace(reSeasonEpTag.ReplaceAllString(cleaned, ""))
581599

582600
// Remove decimal version numbers at the end like "3.5" (but NOT "Season 2")
583-
re5 := regexp.MustCompile(`\s+\d+\.\d+\s*$`)
584-
cleaned = strings.TrimSpace(re5.ReplaceAllString(cleaned, ""))
601+
cleaned = strings.TrimSpace(reDecimalSuffix.ReplaceAllString(cleaned, ""))
585602

586603
// Remove episode count like "(171 episodes)" or "(1 eps)" or Portuguese equivalents
587-
re7 := regexp.MustCompile(`(?i)\s*\(\d+\s+(?:episodes?|eps?|epis[oó]dios?)\)`)
588-
cleaned = strings.TrimSpace(re7.ReplaceAllString(cleaned, ""))
604+
cleaned = strings.TrimSpace(reEpCount.ReplaceAllString(cleaned, ""))
589605

590606
// Remove 9Anime-style episode info like "(HD SUB DUB Ep 170/170)" or "(SUB Ep 12/12)"
591-
re9anime := regexp.MustCompile(`(?i)\s*\((?:HD\s+)?(?:(?:SUB|DUB)\s+)*Ep\s+\d+/\d+\)`)
592-
cleaned = strings.TrimSpace(re9anime.ReplaceAllString(cleaned, ""))
607+
cleaned = strings.TrimSpace(re9AnimeEpInfo.ReplaceAllString(cleaned, ""))
593608

594609
// Remove special titles and additions after colon
595-
re8 := regexp.MustCompile(`(?i):\s*(?:Jump Festa \d+|The All Magic Knights|Sword of the Wizard King|Mahou Tei no Ken).*$`)
596-
cleaned = strings.TrimSpace(re8.ReplaceAllString(cleaned, ""))
610+
cleaned = strings.TrimSpace(reSpecialTitles.ReplaceAllString(cleaned, ""))
597611

598612
// Remove N/A ratings and similar suffixes
599-
re9 := regexp.MustCompile(`(?i)\s+N/A\s*$`)
600-
cleaned = strings.TrimSpace(re9.ReplaceAllString(cleaned, ""))
613+
cleaned = strings.TrimSpace(reNASuffix.ReplaceAllString(cleaned, ""))
601614

602615
// Remove rating scores like "7.12" or "8.5" at the end (only decimal numbers)
603-
re10 := regexp.MustCompile(`\s+\d+\.\d+\s*$`)
604-
cleaned = strings.TrimSpace(re10.ReplaceAllString(cleaned, ""))
616+
cleaned = strings.TrimSpace(reDecimalSuffix.ReplaceAllString(cleaned, ""))
605617

606618
// Remove empty parentheses that may be left after other cleanups
607-
reEmptyParens := regexp.MustCompile(`\s*\(\s*\)`)
608619
cleaned = strings.TrimSpace(reEmptyParens.ReplaceAllString(cleaned, ""))
609620

610621
// Remove trailing colons that may be left after removing season/part info
@@ -618,13 +629,13 @@ func CleanTitle(title string) string {
618629

619630
// Replace hyphens with spaces (for URL-style names like "black-clover")
620631
// But only if surrounded by letters (not em-dashes already handled above)
621-
cleaned = regexp.MustCompile(`([a-zA-Z])-([a-zA-Z])`).ReplaceAllString(cleaned, "$1 $2")
632+
cleaned = reHyphenLetters.ReplaceAllString(cleaned, "$1 $2")
622633

623634
// Replace underscores with spaces
624635
cleaned = strings.ReplaceAll(cleaned, "_", " ")
625636

626637
// Normalize whitespace
627-
cleaned = regexp.MustCompile(`\s+`).ReplaceAllString(cleaned, " ")
638+
cleaned = reWhitespaceRun.ReplaceAllString(cleaned, " ")
628639
cleaned = strings.TrimSpace(cleaned)
629640

630641
util.Debugf("CleanTitle: '%s' -> '%s'", title, cleaned)

internal/api/perf_bench_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package api
2+
3+
import "testing"
4+
5+
// Benchmark inputs mirror real titles produced by the PT-BR and English
6+
// scrapers so the numbers reflect the actual search hot path.
7+
var benchTitles = []string{
8+
"🔥[AnimeFire] Naruto Shippuuden Dublado - Todos os Episódios",
9+
"[PT-BR] Jujutsu Kaisen 2ª Temporada (Dublado) 8.39 A16",
10+
"[English] Black Clover (170 episodes) N/A",
11+
"[Movies/TV] One Piece Film: Red – Todos os Episódios",
12+
"Shingeki no Kyojin: The Final Season Parte 2 Legendado",
13+
"black-clover-dublado",
14+
}
15+
16+
func BenchmarkCleanTitle(b *testing.B) {
17+
b.ReportAllocs()
18+
for i := 0; i < b.N; i++ {
19+
for _, title := range benchTitles {
20+
CleanTitle(title)
21+
}
22+
}
23+
}
24+
25+
func BenchmarkGenerateSearchVariations(b *testing.B) {
26+
b.ReportAllocs()
27+
for i := 0; i < b.N; i++ {
28+
generateSearchVariations("Naruto Shippuuden Clássico III")
29+
}
30+
}

internal/api/providers/metadata/metadata.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -465,17 +465,19 @@ func inferSeasonNumber(titles ...string) int {
465465
return 0
466466
}
467467

468+
// seasonNumberPatterns match "Season N" / "Nth Season" markers in titles.
469+
var seasonNumberPatterns = []*regexp.Regexp{
470+
regexp.MustCompile(`(?i)\bseason\s+(\d+)\b`),
471+
regexp.MustCompile(`(?i)\b(\d+)\s*(?:st|nd|rd|th)?\s+season\b`),
472+
}
473+
468474
func inferSeasonNumberFromTitle(title string) int {
469475
title = strings.TrimSpace(title)
470476
if title == "" {
471477
return 0
472478
}
473479

474-
patterns := []*regexp.Regexp{
475-
regexp.MustCompile(`(?i)\bseason\s+(\d+)\b`),
476-
regexp.MustCompile(`(?i)\b(\d+)\s*(?:st|nd|rd|th)?\s+season\b`),
477-
}
478-
for _, pattern := range patterns {
480+
for _, pattern := range seasonNumberPatterns {
479481
matches := pattern.FindStringSubmatch(title)
480482
if len(matches) < 2 {
481483
continue

internal/api/providers/naming/naming.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,14 @@ type MediaInfo struct {
5454
// sanitize removes characters not allowed in filenames across OS.
5555
var unsafeChars = regexp.MustCompile(`[<>:"/\\|?*\x00-\x1f]`)
5656

57+
// spaceRun collapses runs of whitespace left by sanitization.
58+
var spaceRun = regexp.MustCompile(`\s{2,}`)
59+
5760
// SanitizeFilename removes characters unsafe for filenames on all platforms.
5861
func SanitizeFilename(name string) string {
5962
clean := unsafeChars.ReplaceAllString(name, "")
6063
clean = strings.TrimSpace(clean)
6164
// Collapse multiple spaces
62-
spaceRun := regexp.MustCompile(`\s{2,}`)
6365
clean = spaceRun.ReplaceAllString(clean, " ")
6466
// Remove trailing dots (Windows)
6567
clean = strings.TrimRight(clean, ".")
@@ -69,9 +71,11 @@ func SanitizeFilename(name string) string {
6971
return clean
7072
}
7173

74+
// tagPattern matches source/language tags stripped by CleanTitle.
75+
var tagPattern = regexp.MustCompile(`\s*\[(?:English|PT-BR|Portuguese|Multilanguage|AllAnime|AnimeFire|AnimeDrive|Goyabu|SuperFlix|FlixHQ|SFlix|9Anime|Movie|TV)\]`)
76+
7277
// CleanTitle removes source tags like [English], [PT-BR], [AllAnime] etc. from a title.
7378
func CleanTitle(title string) string {
74-
tagPattern := regexp.MustCompile(`\s*\[(?:English|PT-BR|Portuguese|Multilanguage|AllAnime|AnimeFire|AnimeDrive|Goyabu|SuperFlix|FlixHQ|SFlix|9Anime|Movie|TV)\]`)
7579
clean := tagPattern.ReplaceAllString(title, "")
7680
clean = strings.TrimSpace(clean)
7781
if clean == "" {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package naming
2+
3+
import "testing"
4+
5+
func BenchmarkSanitizeFilename(b *testing.B) {
6+
b.ReportAllocs()
7+
for i := 0; i < b.N; i++ {
8+
SanitizeFilename(`Fate/stay night: Unlimited Blade Works <Episode 12?>`)
9+
}
10+
}
11+
12+
func BenchmarkCleanTitle(b *testing.B) {
13+
b.ReportAllocs()
14+
for i := 0; i < b.N; i++ {
15+
CleanTitle("[PT-BR] [SuperFlix] Vinland Saga [TV]")
16+
}
17+
}

internal/downloader/hls/hls.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,9 @@ func (d *Downloader) parsePlaylist(ctx context.Context, url string, headers map[
194194
return d.parseMediaPlaylistLines(masterPlaylistLines, url)
195195
}
196196

197+
// bandwidthRe extracts the BANDWIDTH attribute from #EXT-X-STREAM-INF tags.
198+
var bandwidthRe = regexp.MustCompile(`BANDWIDTH=(\d+)`)
199+
197200
// selectBestStream finds the highest quality stream from a master playlist
198201
func (d *Downloader) selectBestStream(lines []string, baseURL string) string {
199202
type StreamInfo struct {
@@ -207,7 +210,7 @@ func (d *Downloader) selectBestStream(lines []string, baseURL string) string {
207210
if strings.HasPrefix(line, "#EXT-X-STREAM-INF:") {
208211
// Parse bandwidth from the tag
209212
bandwidth := 0
210-
if bwMatch := regexp.MustCompile(`BANDWIDTH=(\d+)`).FindStringSubmatch(line); len(bwMatch) > 1 {
213+
if bwMatch := bandwidthRe.FindStringSubmatch(line); len(bwMatch) > 1 {
211214
if bw, err := strconv.Atoi(bwMatch[1]); err == nil {
212215
bandwidth = bw
213216
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package hls
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
)
7+
8+
func BenchmarkSelectBestStream(b *testing.B) {
9+
dl := &Downloader{}
10+
baseURL := "https://cdn.example.com/video/master.m3u8"
11+
12+
// Master playlist with 8 quality variants — typical for large CDNs.
13+
var lines []string
14+
lines = append(lines, "#EXTM3U")
15+
for i := 1; i <= 8; i++ {
16+
lines = append(lines,
17+
fmt.Sprintf("#EXT-X-STREAM-INF:BANDWIDTH=%d,RESOLUTION=1920x1080", i*500000),
18+
fmt.Sprintf("variant%d.m3u8", i),
19+
)
20+
}
21+
22+
b.ReportAllocs()
23+
b.ResetTimer()
24+
for i := 0; i < b.N; i++ {
25+
dl.selectBestStream(lines, baseURL)
26+
}
27+
}

internal/player/scraper.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ var (
4343
bhRe = regexp.MustCompile(`"cfb2h"\s*:\s*"([^"]+)"`)
4444
atRe = regexp.MustCompile(`"SNlM0e"\s*:\s*"([^"]+)"`)
4545
extractResolutionRe = regexp.MustCompile(`(\d+)p?`)
46+
googleVideoRe = regexp.MustCompile(`https://[^"\\]+\.googlevideo\.com/[^"\\]+`)
4647
episodePatternREs = []*regexp.Regexp{
4748
regexp.MustCompile(`(?i)epis[oó]dio\s+(\d+)`),
4849
regexp.MustCompile(`(?i)episode\s+(\d+)`),
@@ -891,7 +892,6 @@ func parseBatchexecuteResponse(body []byte) (string, error) {
891892

892893
// Regex fallback: scan the raw body for any *.googlevideo.com URL.
893894
if videoURL == "" {
894-
googleVideoRe := regexp.MustCompile(`https://[^"\\]+\.googlevideo\.com/[^"\\]+`)
895895
if match := googleVideoRe.FindString(string(body)); match != "" {
896896
util.Debugf("Blogger batchexecute: found googlevideo URL via regex fallback")
897897
videoURL = match

internal/scraper/manager.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ func (a *AllAnimeAdapter) GetAnimeEpisodes(animeURL string) ([]models.Episode, e
178178
return nil, err
179179
}
180180

181-
var episodeModels []models.Episode
181+
episodeModels := make([]models.Episode, 0, len(episodes))
182182
for i, ep := range episodes {
183183
episodeModels = append(episodeModels, models.Episode{
184184
Number: ep,

0 commit comments

Comments
 (0)