Added recommended anime page (experimental)
This commit is contained in:
parent
fa6fca84a6
commit
4344da7752
@ -42,6 +42,7 @@ import (
|
|||||||
"github.com/animenotifier/notify.moe/pages/popular"
|
"github.com/animenotifier/notify.moe/pages/popular"
|
||||||
"github.com/animenotifier/notify.moe/pages/posts"
|
"github.com/animenotifier/notify.moe/pages/posts"
|
||||||
"github.com/animenotifier/notify.moe/pages/profile"
|
"github.com/animenotifier/notify.moe/pages/profile"
|
||||||
|
"github.com/animenotifier/notify.moe/pages/recommended"
|
||||||
"github.com/animenotifier/notify.moe/pages/search"
|
"github.com/animenotifier/notify.moe/pages/search"
|
||||||
"github.com/animenotifier/notify.moe/pages/settings"
|
"github.com/animenotifier/notify.moe/pages/settings"
|
||||||
"github.com/animenotifier/notify.moe/pages/shop"
|
"github.com/animenotifier/notify.moe/pages/shop"
|
||||||
@ -147,6 +148,7 @@ func Configure(app *aero.Application) {
|
|||||||
l.Page("/user/:nick/animelist/hold", animelist.FilterByStatus(arn.AnimeListStatusHold))
|
l.Page("/user/:nick/animelist/hold", animelist.FilterByStatus(arn.AnimeListStatusHold))
|
||||||
l.Page("/user/:nick/animelist/dropped", animelist.FilterByStatus(arn.AnimeListStatusDropped))
|
l.Page("/user/:nick/animelist/dropped", animelist.FilterByStatus(arn.AnimeListStatusDropped))
|
||||||
l.Page("/user/:nick/animelist/anime/:id", animelistitem.Get)
|
l.Page("/user/:nick/animelist/anime/:id", animelistitem.Get)
|
||||||
|
l.Page("/user/:nick/recommended/anime", recommended.Anime)
|
||||||
|
|
||||||
// Anime list
|
// Anime list
|
||||||
l.Page("/animelist/watching", home.FilterByStatus(arn.AnimeListStatusWatching))
|
l.Page("/animelist/watching", home.FilterByStatus(arn.AnimeListStatusWatching))
|
||||||
|
89
pages/recommended/anime.go
Normal file
89
pages/recommended/anime.go
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
package recommended
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/aerogo/aero"
|
||||||
|
"github.com/animenotifier/arn"
|
||||||
|
"github.com/animenotifier/notify.moe/components"
|
||||||
|
)
|
||||||
|
|
||||||
|
const maxRecommendations = 20
|
||||||
|
|
||||||
|
// Anime shows a list of recommended anime.
|
||||||
|
func Anime(ctx *aero.Context) string {
|
||||||
|
nick := ctx.Get("nick")
|
||||||
|
user, err := arn.GetUserByNick(nick)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return ctx.Error(http.StatusUnauthorized, "Not logged in", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
animeList := user.AnimeList()
|
||||||
|
genreItems := animeList.Genres()
|
||||||
|
genreAffinity := map[string]float64{}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all anime
|
||||||
|
recommendations := 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 {
|
||||||
|
// Skip anime from my list (except planned anime)
|
||||||
|
existing := animeList.Find(anime.ID)
|
||||||
|
|
||||||
|
if existing != nil && existing.Status != arn.AnimeListStatusPlanned {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
affinity[anime.ID] = float64(anime.Popularity.Total())
|
||||||
|
|
||||||
|
// animeGenresAffinity := 0.0
|
||||||
|
|
||||||
|
// if len(anime.Genres) > 0 {
|
||||||
|
// for _, genre := range anime.Genres {
|
||||||
|
// if genreAffinity[genre] > animeGenresAffinity {
|
||||||
|
// animeGenresAffinity = genreAffinity[genre]
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// animeGenresAffinity = animeGenresAffinity / float64(len(anime.Genres))
|
||||||
|
// }
|
||||||
|
|
||||||
|
// affinity[anime.ID] = animeGenresAffinity
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort
|
||||||
|
sort.Slice(recommendations, func(i, j int) bool {
|
||||||
|
return affinity[recommendations[i].ID] > affinity[recommendations[j].ID]
|
||||||
|
})
|
||||||
|
|
||||||
|
// Take the top 10
|
||||||
|
if len(recommendations) > maxRecommendations {
|
||||||
|
recommendations = recommendations[:maxRecommendations]
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.HTML(components.RecommendedAnime(recommendations, user))
|
||||||
|
}
|
7
pages/recommended/anime.pixy
Normal file
7
pages/recommended/anime.pixy
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
component RecommendedAnime(animes []*arn.Anime, user *arn.User)
|
||||||
|
h1= "Recommended anime for " + user.Nick
|
||||||
|
|
||||||
|
AnimeGrid(animes, user)
|
||||||
|
//- ul
|
||||||
|
//- each anime in animes
|
||||||
|
//- li= anime.Title.Canonical
|
Loading…
Reference in New Issue
Block a user