From 6d3199a75492b7477dcab8a453c23308b0af614c Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Fri, 23 Mar 2018 23:48:15 +0100 Subject: [PATCH] Recommendations split into TV and movies --- pages/companies/popular.scarlet | 1 + pages/recommended/anime.go | 95 ++++++++++++--------------------- pages/recommended/anime.pixy | 15 ++++-- pages/recommended/anime.scarlet | 5 ++ scripts/Application.ts | 1 - 5 files changed, 53 insertions(+), 64 deletions(-) create mode 100644 pages/recommended/anime.scarlet diff --git a/pages/companies/popular.scarlet b/pages/companies/popular.scarlet index 4f1d56f9..25e47814 100644 --- a/pages/companies/popular.scarlet +++ b/pages/companies/popular.scarlet @@ -12,6 +12,7 @@ const popular-company-height = 246px padding 0.5rem 0.75rem overflow hidden ui-element + box-shadow shadow-light .popular-company-header margin-bottom 0.5rem diff --git a/pages/recommended/anime.go b/pages/recommended/anime.go index ec11b5b5..fa83ac8d 100644 --- a/pages/recommended/anime.go +++ b/pages/recommended/anime.go @@ -11,8 +11,7 @@ import ( ) const ( - maxRecommendations = 20 - worstGenreCount = 5 + maxRecommendations = 10 ) // Anime shows a list of recommended anime. @@ -26,51 +25,28 @@ func Anime(ctx *aero.Context) string { } animeList := viewUser.AnimeList() - genreItems := animeList.Genres() - genreAffinity := map[string]float64{} - worstGenres := []string{} - - for genre, animeListItems := range genreItems { - affinity := 0.0 - - for _, item := range animeListItems { - // if item.Status == arn.AnimeListStatusDropped { - // affinity -= 5.0 - // continue - // } - - if item.Rating.Overall != 0 { - affinity += item.Rating.Overall - } else { - affinity += 5.0 - } - } - - genreAffinity[genre] = affinity - worstGenres = append(worstGenres, genre) - } - - sort.Slice(worstGenres, func(i, j int) bool { - return genreAffinity[worstGenres[i]] < genreAffinity[worstGenres[j]] - }) - - if len(worstGenres) > worstGenreCount { - worstGenres = worstGenres[:worstGenreCount] - } // Get all anime - recommendations := arn.AllAnime() + var tv []*arn.Anime + var movies []*arn.Anime + allAnime := arn.AllAnime() // Affinity maps an anime ID to a number that indicates how likely a user is going to enjoy that anime. affinity := map[string]float64{} // Calculate affinity for each anime - for _, anime := range recommendations { + for _, anime := range allAnime { // Skip anime that are upcoming or tba if anime.Status == "upcoming" || anime.Status == "tba" { continue } + if anime.Type == "tv" { + tv = append(tv, anime) + } else if anime.Type == "movie" { + movies = append(movies, anime) + } + // Skip anime from my list (except planned anime) existing := animeList.Find(anime.ID) @@ -78,48 +54,47 @@ func Anime(ctx *aero.Context) string { continue } - // Skip anime that don't have one of the top genres for that user - worstGenreFound := false - - for _, genre := range anime.Genres { - if arn.Contains(worstGenres, genre) { - worstGenreFound = true - break - } - } - - if worstGenreFound { - continue - } - - animeAffinity := 0.0 + animeAffinity := anime.Score() // Planned anime go higher if existing != nil && existing.Status == arn.AnimeListStatusPlanned { - animeAffinity += 75.0 + animeAffinity += 15.0 } - animeAffinity += float64(anime.Popularity.Total()) - animeAffinity += anime.Rating.Overall * 80 affinity[anime.ID] = animeAffinity } // Sort - sort.Slice(recommendations, func(i, j int) bool { - affinityA := affinity[recommendations[i].ID] - affinityB := affinity[recommendations[j].ID] + sort.Slice(tv, func(i, j int) bool { + affinityA := affinity[tv[i].ID] + affinityB := affinity[tv[j].ID] if affinityA == affinityB { - return recommendations[i].Title.Canonical < recommendations[j].Title.Canonical + return tv[i].Title.Canonical < tv[j].Title.Canonical + } + + return affinityA > affinityB + }) + + sort.Slice(movies, func(i, j int) bool { + affinityA := affinity[movies[i].ID] + affinityB := affinity[movies[j].ID] + + if affinityA == affinityB { + return movies[i].Title.Canonical < movies[j].Title.Canonical } return affinityA > affinityB }) // Take the top 10 - if len(recommendations) > maxRecommendations { - recommendations = recommendations[:maxRecommendations] + if len(tv) > maxRecommendations { + tv = tv[:maxRecommendations] } - return ctx.HTML(components.RecommendedAnime(recommendations, worstGenres, viewUser, user)) + if len(movies) > maxRecommendations { + movies = movies[:maxRecommendations] + } + + return ctx.HTML(components.RecommendedAnime(tv, movies, viewUser, user)) } diff --git a/pages/recommended/anime.pixy b/pages/recommended/anime.pixy index d0df54bb..c2b2a210 100644 --- a/pages/recommended/anime.pixy +++ b/pages/recommended/anime.pixy @@ -1,4 +1,13 @@ -component RecommendedAnime(animes []*arn.Anime, worstGenres []string, viewUser *arn.User, user *arn.User) - h1(title="This is a machine-generated list of anime recommendations.")= "Recommended anime for " + viewUser.Nick +component RecommendedAnime(animes []*arn.Anime, movies []*arn.Anime, viewUser *arn.User, user *arn.User) + h1= "Recommendations for " + viewUser.Nick + + h2.recommendations-category + Icon("tv") + span TV series + AnimeGrid(animes, user) + + h2.recommendations-category + Icon("film") + span Movies - AnimeGrid(animes, user) \ No newline at end of file + AnimeGrid(movies, user) \ No newline at end of file diff --git a/pages/recommended/anime.scarlet b/pages/recommended/anime.scarlet new file mode 100644 index 00000000..25fa9d2f --- /dev/null +++ b/pages/recommended/anime.scarlet @@ -0,0 +1,5 @@ +.recommendations-category + text-align left + font-size 1.8rem + border-bottom ui-border + padding-bottom 1rem \ No newline at end of file diff --git a/scripts/Application.ts b/scripts/Application.ts index 0e88530d..8b78d239 100644 --- a/scripts/Application.ts +++ b/scripts/Application.ts @@ -163,7 +163,6 @@ export class Application { } // Don't ajaxify invalid links, links with a target or links that disable ajax specifically - console.log(link.hash) if(link.href === "" || link.href.includes("#") || link.target.length > 0 || link.dataset.ajax === "false") { continue }