diff --git a/main.go b/main.go index 23f79b31..2d47d72e 100644 --- a/main.go +++ b/main.go @@ -24,6 +24,7 @@ import ( "github.com/animenotifier/notify.moe/pages/forums" "github.com/animenotifier/notify.moe/pages/listimport" "github.com/animenotifier/notify.moe/pages/listimport/listimportanilist" + "github.com/animenotifier/notify.moe/pages/listimport/listimportkitsu" "github.com/animenotifier/notify.moe/pages/listimport/listimportmyanimelist" "github.com/animenotifier/notify.moe/pages/login" "github.com/animenotifier/notify.moe/pages/music" @@ -112,6 +113,8 @@ func configure(app *aero.Application) *aero.Application { app.Ajax("/import/anilist/animelist/finish", listimportanilist.Finish) app.Ajax("/import/myanimelist/animelist", listimportmyanimelist.Preview) app.Ajax("/import/myanimelist/animelist/finish", listimportmyanimelist.Finish) + app.Ajax("/import/kitsu/animelist", listimportkitsu.Preview) + app.Ajax("/import/kitsu/animelist/finish", listimportkitsu.Finish) // Genres // app.Ajax("/genres", genres.Get) diff --git a/pages/listimport/listimport.pixy b/pages/listimport/listimport.pixy index eaac0fbe..17a65ab6 100644 --- a/pages/listimport/listimport.pixy +++ b/pages/listimport/listimport.pixy @@ -6,6 +6,13 @@ component ImportLists(user *arn.User) a.button.mountable.ajax(href="/import/anilist/animelist") Icon("download") span Import AniList + + if user.Accounts.Kitsu.Nick != "" + label Kitsu: + .widget-input + a.button.mountable.ajax(href="/import/kitsu/animelist") + Icon("download") + span Import Kitsu if user.Accounts.MyAnimeList.Nick != "" label MyAnimeList: diff --git a/pages/listimport/listimportkitsu/kitsu.go b/pages/listimport/listimportkitsu/kitsu.go new file mode 100644 index 00000000..ebdcd7a3 --- /dev/null +++ b/pages/listimport/listimportkitsu/kitsu.go @@ -0,0 +1,133 @@ +package listimportkitsu + +import ( + "net/http" + + "github.com/aerogo/aero" + "github.com/animenotifier/arn" + "github.com/animenotifier/kitsu" + "github.com/animenotifier/notify.moe/components" + "github.com/animenotifier/notify.moe/utils" +) + +// Preview shows an import preview. +func Preview(ctx *aero.Context) string { + user := utils.GetUser(ctx) + + if user == nil { + return ctx.Error(http.StatusBadRequest, "Not logged in", nil) + } + + matches, response := getMatches(ctx) + + if response != "" { + return response + } + + return ctx.HTML(components.ImportKitsu(user, matches)) +} + +// Finish ... +func Finish(ctx *aero.Context) string { + user := utils.GetUser(ctx) + + if user == nil { + return ctx.Error(http.StatusBadRequest, "Not logged in", nil) + } + + matches, response := getMatches(ctx) + + if response != "" { + return response + } + + animeList := user.AnimeList() + + for _, match := range matches { + if match.ARNAnime == nil || match.KitsuItem == nil { + continue + } + + rating := match.KitsuItem.Attributes.RatingTwenty + + if rating < 2 { + rating = 2 + } + + if rating > 20 { + rating = 20 + } + + // Convert rating + convertedRating := (float64(rating-2) / 18.0) * 10.0 + + item := &arn.AnimeListItem{ + AnimeID: match.ARNAnime.ID, + Status: arn.KitsuStatusToARNStatus(match.KitsuItem.Attributes.Status), + Episodes: match.KitsuItem.Attributes.Progress, + Notes: match.KitsuItem.Attributes.Notes, + Rating: &arn.AnimeRating{ + Overall: convertedRating, + }, + RewatchCount: match.KitsuItem.Attributes.ReconsumeCount, + Created: arn.DateTimeUTC(), + Edited: arn.DateTimeUTC(), + } + + animeList.Import(item) + } + + err := animeList.Save() + + if err != nil { + return ctx.Error(http.StatusInternalServerError, "Error saving your anime list", err) + } + + return ctx.Redirect("/+" + user.Nick + "/animelist") +} + +// getMatches finds and returns all matches for the logged in user. +func getMatches(ctx *aero.Context) ([]*arn.KitsuMatch, string) { + user := utils.GetUser(ctx) + + if user == nil { + return nil, ctx.Error(http.StatusBadRequest, "Not logged in", nil) + } + + kitsuUser, err := kitsu.GetUser(user.Accounts.Kitsu.Nick) + + if err != nil { + return nil, ctx.Error(http.StatusBadRequest, "Couldn't load your user info from Kitsu", err) + } + + library := kitsuUser.StreamLibraryEntries() + matches := findAllMatches(library) + + return matches, "" +} + +// findAllMatches returns all matches for the anime inside an anilist anime list. +func findAllMatches(library chan *kitsu.LibraryEntry) []*arn.KitsuMatch { + matches := []*arn.KitsuMatch{} + + for item := range library { + // Ignore non-anime entries + if item.Anime == nil { + continue + } + + var anime *arn.Anime + connection, err := arn.GetKitsuToAnime(item.Anime.ID) + + if err == nil { + anime, _ = arn.GetAnime(connection.AnimeID) + } + + matches = append(matches, &arn.KitsuMatch{ + KitsuItem: item, + ARNAnime: anime, + }) + } + + return matches +} diff --git a/pages/listimport/listimportkitsu/kitsu.pixy b/pages/listimport/listimportkitsu/kitsu.pixy new file mode 100644 index 00000000..1a39b7a8 --- /dev/null +++ b/pages/listimport/listimportkitsu/kitsu.pixy @@ -0,0 +1,23 @@ +component ImportKitsu(user *arn.User, matches []*arn.KitsuMatch) + h1= "kitsu.io Import (" + user.Accounts.Kitsu.Nick + ", " + toString(len(matches)) + " anime)" + + table.import-list + thead + tr + th kitsu.io + th notify.moe + tbody + each match in matches + tr + td + a(href=match.KitsuItem.Anime.Link(), target="_blank", rel="noopener")= match.KitsuItem.Anime.Attributes.CanonicalTitle + td + if match.ARNAnime == nil + span.import-error Not found on notify.moe + else + a(href=match.ARNAnime.Link(), target="_blank", rel="noopener")= match.ARNAnime.Title.Canonical + + .buttons + a.button.mountable(href="/import/kitsu/animelist/finish") + Icon("refresh") + span Import \ No newline at end of file diff --git a/tests.go b/tests.go index 7fe2a5ed..fdc299a8 100644 --- a/tests.go +++ b/tests.go @@ -183,6 +183,8 @@ var routeTests = map[string][]string{ "/import/anilist/animelist/finish": nil, "/import/myanimelist/animelist": nil, "/import/myanimelist/animelist/finish": nil, + "/import/kitsu/animelist": nil, + "/import/kitsu/animelist/finish": nil, "/anime/:id/edit": nil, "/new/thread": nil, "/new/soundtrack": nil,