Fix SPA routing and frontend search duplicates
This commit is contained in:
parent
0230054f92
commit
1bd470731c
5 changed files with 88 additions and 29 deletions
|
|
@ -118,6 +118,20 @@ func FileServer(r chi.Router, path string, root http.FileSystem) {
|
|||
r.Get(path, func(w http.ResponseWriter, r *http.Request) {
|
||||
rctx := chi.RouteContext(r.Context())
|
||||
pathPrefix := strings.TrimSuffix(rctx.RoutePattern(), "/*")
|
||||
reqPath := strings.TrimPrefix(r.URL.Path, pathPrefix)
|
||||
if reqPath == "" {
|
||||
reqPath = "/"
|
||||
}
|
||||
|
||||
// Check if file exists in the static directory
|
||||
f, err := root.Open(reqPath)
|
||||
if err == nil {
|
||||
f.Close()
|
||||
} else {
|
||||
// If not found, rewrite path to serve index.html for SPA routing
|
||||
r.URL.Path = pathPrefix + "/index.html"
|
||||
}
|
||||
|
||||
fs := http.StripPrefix(pathPrefix, http.FileServer(root))
|
||||
fs.ServeHTTP(w, r)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -236,35 +236,36 @@ func (s *PhimMoiChillScraper) GetMovieDetail(slug string) (*models.RophimMovie,
|
|||
}
|
||||
})
|
||||
|
||||
// Fallback: If no episodes found, finding "Xem phim" button for single movie
|
||||
if len(episodes) == 0 {
|
||||
// Common selectors for "Watch" button: .btn-watch, a:contains("Xem phim")
|
||||
watchBtn := doc.Find("a.btn-watch, a.btn-see, ul.btn-block a")
|
||||
if watchBtn.Length() > 0 {
|
||||
href, _ := watchBtn.Attr("href")
|
||||
if strings.Contains(href, "/xem/") {
|
||||
episodes = append(episodes, models.Episode{
|
||||
Number: 1,
|
||||
Title: "Full",
|
||||
URL: href,
|
||||
ServerName: "PhimMoiChill",
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// Try text content
|
||||
doc.Find("a").Each(func(i int, s *goquery.Selection) {
|
||||
if strings.Contains(strings.ToLower(s.Text()), "xem phim") {
|
||||
href, _ := s.Attr("href")
|
||||
if strings.Contains(href, "/xem/") {
|
||||
episodes = append(episodes, models.Episode{
|
||||
Number: 1,
|
||||
Title: "Full",
|
||||
URL: href,
|
||||
ServerName: "PhimMoiChill",
|
||||
})
|
||||
return // Break
|
||||
}
|
||||
// Fallback/Main: Find "Xem phim" button which is often Episode 1 for series,
|
||||
// or the only episode for movies. We always check this, not just when len(episodes)==0.
|
||||
watchBtn := doc.Find("a.btn-watch, a.btn-see, ul.btn-block a")
|
||||
var watchHref string
|
||||
if watchBtn.Length() > 0 {
|
||||
watchHref, _ = watchBtn.Attr("href")
|
||||
} else {
|
||||
doc.Find("a").Each(func(i int, s *goquery.Selection) {
|
||||
if strings.Contains(strings.ToLower(s.Text()), "xem phim") {
|
||||
href, _ := s.Attr("href")
|
||||
if strings.Contains(href, "/xem/") {
|
||||
watchHref = href
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if watchHref != "" && strings.Contains(watchHref, "/xem/") {
|
||||
// Only add if Episode 1 is not already present
|
||||
if _, exists := epMap[1]; !exists {
|
||||
epMap[1] = len(episodes)
|
||||
title := "Tập 1"
|
||||
if len(episodes) == 0 {
|
||||
title = "Full"
|
||||
}
|
||||
episodes = append(episodes, models.Episode{
|
||||
Number: 1,
|
||||
Title: title,
|
||||
URL: watchHref,
|
||||
ServerName: "PhimMoiChill",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
19
backend/test_movie.go
Normal file
19
backend/test_movie.go
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"streamflow-backend/internal/scraper"
|
||||
)
|
||||
|
||||
func main() {
|
||||
p := scraper.NewPhimMoiChillScraper()
|
||||
movie, err := p.GetMovieDetail("vu-tru-cua-doi-ta-pm17193")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
b, _ := json.MarshalIndent(movie, "", " ")
|
||||
fmt.Println(string(b))
|
||||
}
|
||||
19
backend/test_search.go
Normal file
19
backend/test_search.go
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"streamflow-backend/internal/scraper"
|
||||
)
|
||||
|
||||
func main() {
|
||||
p := scraper.NewPhimMoiChillScraper()
|
||||
movies, err := p.Search("vũ trụ của đôi ta", 1)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
b, _ := json.MarshalIndent(movies, "", " ")
|
||||
fmt.Println(string(b))
|
||||
}
|
||||
|
|
@ -68,7 +68,13 @@ export const HomeContent = ({ topPadding = "pt-24" }: HomeContentProps) => {
|
|||
if (!data || data.length === 0) {
|
||||
setHasMore(false);
|
||||
} else {
|
||||
setMovies(prev => page === 1 ? data : [...prev, ...data]);
|
||||
setMovies(prev => {
|
||||
if (page === 1) return data;
|
||||
// Deduplicate arrays when appending to prevent React StrictMode or fast-scroll double fetches
|
||||
const existingIds = new Set(prev.map(m => m.id));
|
||||
const newUniqueMovies = data.filter((m: Movie) => !existingIds.has(m.id));
|
||||
return [...prev, ...newUniqueMovies];
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
console.error("Failed to fetch movies");
|
||||
|
|
|
|||
Loading…
Reference in a new issue