From 71dc30c02de604f5b855a56461a435d30f7d2c60 Mon Sep 17 00:00:00 2001 From: Alex Perathoner Date: Sat, 9 Nov 2024 14:38:23 +0100 Subject: [PATCH] Better search --- server/content.go | 21 +++++- server/import.go | 77 ++++++++++++++++++-- src/routes/(app)/import/process/+page.svelte | 16 ++-- 3 files changed, 98 insertions(+), 16 deletions(-) diff --git a/server/content.go b/server/content.go index 4d81d75c..b0c7833b 100644 --- a/server/content.go +++ b/server/content.go @@ -257,11 +257,20 @@ func searchContent(query string, pageNum int) (TMDBSearchMultiResponse, error) { } func searchMovies(query string, pageNum int) (TMDBSearchMoviesResponse, error) { + return searchMoviesWithYear(query, pageNum, 0) +} + +func searchMoviesWithYear(query string, pageNum int, year int) (TMDBSearchMoviesResponse, error) { resp := new(TMDBSearchMoviesResponse) if pageNum == 0 { pageNum = 1 } - err := tmdbRequest("/search/movie", map[string]string{"query": query, "page": strconv.Itoa(pageNum)}, &resp) + params := map[string]string{"query": query, "page": strconv.Itoa(pageNum)} + if year != 0 { + params["year"] = strconv.Itoa(year) + } + err := tmdbRequest("/search/movie", params, &resp) + if err != nil { slog.Error("Failed to complete movie search request!", "error", err.Error()) return TMDBSearchMoviesResponse{}, errors.New("failed to complete movie search request") @@ -273,11 +282,19 @@ func searchMovies(query string, pageNum int) (TMDBSearchMoviesResponse, error) { } func searchTv(query string, pageNum int) (TMDBSearchShowsResponse, error) { + return searchTvWithYear(query, pageNum, 0) +} + +func searchTvWithYear(query string, pageNum int, year int) (TMDBSearchShowsResponse, error) { resp := new(TMDBSearchShowsResponse) if pageNum == 0 { pageNum = 1 } - err := tmdbRequest("/search/tv", map[string]string{"query": query, "page": strconv.Itoa(pageNum)}, &resp) + params := map[string]string{"query": query, "page": strconv.Itoa(pageNum)} + if year != 0 { + params["year"] = strconv.Itoa(year) + } + err := tmdbRequest("/search/tv", params, &resp) if err != nil { slog.Error("Failed to complete tv search request!", "error", err.Error()) return TMDBSearchShowsResponse{}, errors.New("failed to complete tv search request") diff --git a/server/import.go b/server/import.go index 6de09a12..c8fe3278 100644 --- a/server/import.go +++ b/server/import.go @@ -39,6 +39,7 @@ type ImportRequest struct { WatchedEpisodes []WatchedEpisode `json:"watchedEpisodes"` WatchedSeason []WatchedSeason `json:"watchedSeasons"` Tags []TagAddRequest `json:"tags"` + Year int `json:"year"` } type ImportResponse struct { @@ -72,15 +73,75 @@ func importContent(db *gorm.DB, userId uint, ar ImportRequest) (ImportResponse, } } // tmdbId not passed.. search for the content by name. - sr, err := searchContent(ar.Name, 1) - if err != nil { - slog.Error("import: content search failed", "error", err) - return ImportResponse{}, errors.New("Content search failed") - } + // if a type is passed, use that type to filter the search results. pMatches := []TMDBSearchMultiResults{} - for _, r := range sr.Results { - if r.MediaType != "person" { - pMatches = append(pMatches, r) + if ar.Type == MOVIE { + movieRes, err := searchMoviesWithYear(ar.Name, 1, ar.Year) + if err != nil { + slog.Error("import: content search failed", "error", err) + return ImportResponse{}, errors.New("Content search failed") + } + for _, m := range movieRes.Results { + // Convert []int to []int64 + genreIds := make([]int64, len(m.GenreIds)) + for i, id := range m.GenreIds { + genreIds[i] = int64(id) + } + pMatches = append(pMatches, TMDBSearchMultiResults{ + Adult: m.Adult, + BackdropPath: m.BackdropPath, + GenreIds: genreIds, + ID: m.ID, + OriginalLanguage: m.OriginalLanguage, + Overview: m.Overview, + Popularity: float32(m.Popularity), + PosterPath: m.PosterPath, + Title: m.Title, + VoteAverage: float32(m.VoteAverage), + VoteCount: uint32(m.VoteCount), + MediaType: "movie", + }) + } + } else if ar.Type == SHOW { + tvRes, err := searchTvWithYear(ar.Name, 1, ar.Year) + if err != nil { + slog.Error("import: content search failed", "error", err) + return ImportResponse{}, errors.New("Content search failed") + } + for _, m := range tvRes.Results { + genreIds := make([]int64, len(m.GenreIds)) + for i, id := range m.GenreIds { + genreIds[i] = int64(id) + } + pMatches = append(pMatches, TMDBSearchMultiResults{ + Adult: m.Adult, + BackdropPath: m.BackdropPath, + GenreIds: genreIds, + ID: m.ID, + OriginalLanguage: m.OriginalLanguage, + OriginalName: m.OriginalName, + OriginCountry: m.OriginCountry, + Overview: m.Overview, + Popularity: float32(m.Popularity), + PosterPath: m.PosterPath, + FirstAirDate: m.FirstAirDate, + Name: m.Name, + VoteAverage: float32(m.VoteAverage), + VoteCount: uint32(m.VoteCount), + MediaType: "tv", + }) + } + } + if len(pMatches) == 0 { + sr, err := searchContent(ar.Name, 1) + if err != nil { + slog.Error("import: content search failed", "error", err) + return ImportResponse{}, errors.New("Content search failed") + } + for _, r := range sr.Results { + if r.MediaType != "person" { + pMatches = append(pMatches, r) + } } } resLen := len(pMatches) diff --git a/src/routes/(app)/import/process/+page.svelte b/src/routes/(app)/import/process/+page.svelte index e36dc071..d2c6f2c4 100644 --- a/src/routes/(app)/import/process/+page.svelte +++ b/src/routes/(app)/import/process/+page.svelte @@ -33,6 +33,7 @@ import { onDestroy } from "svelte"; import { get } from "svelte/store"; import papa from "papaparse"; + import Title from "@/lib/content/Title.svelte"; const wList = get(watchedList); @@ -312,8 +313,8 @@ const tags = itemCustomList .map((enabled: number, index: number) => { if (enabled == 1) { - return { name: customLists[index], color: "#ffffff", bgColor: "#04a9ff" }; - } + return { name: "AniList list: " + customLists[index], color: "#ffffff", bgColor: "#04a9ff" }; + } // todo go over favorites, also add a tag for that. }) .filter((t: any) => t); const adjustedRating = item.score / 10; // TODO: update with different scales @@ -330,7 +331,6 @@ const anilistIds = toImport.map((el) => el.anilistId); const allMedia = await doAniListQueryAll(anilistIds); - console.log("allMedia", allMedia); for (let i = 0; i < toImport.length; i++) { try { const el = toImport[i] as any; @@ -369,10 +369,12 @@ let allMedia: any[] = []; let page = 1; const perPage = 50; - while (true) { + const totalIds = anilistIds.length; + + while (allMedia.length < totalIds) { const res = await doAniListQuery(anilistIds, page, perPage); - if (res) { + if (res && res.length > 0) { allMedia.push(...res); page++; } else { @@ -536,7 +538,9 @@ item.state = ImportResponseType.IMPORT_NOTFOUND; rList = rList; return; - } + } // TODO: this also means that thoughts shuold be appended, not replace the other seasons ones; and ratings and status too + // on AniList, each season is a different entry. On TMDB, it's usually the same entry - having "season" in the title prevents us from finding the right element. + item.name = item.name.toLowerCase().includes("season") ? item.name.substring(0, item.name.toLowerCase().indexOf("season")).trim() : item.name; const resp = await axios.post("/import", item); return new Promise((res, rej) => { if (resp.data.type === ImportResponseType.IMPORT_MULTI) {