aboutsummaryrefslogtreecommitdiff
path: root/controllers
diff options
context:
space:
mode:
authorBobby <[email protected]>2026-02-24 16:48:00 +0530
committerBobby <[email protected]>2026-02-24 16:48:00 +0530
commitd3507ae5b9d88a250b444c0e996fa07f84f6e3c5 (patch)
tree64680e5ba7c9b4aa2e412c5bb9611df0e940d971 /controllers
parentc6ff27b989047cf0af8d6cf2aa86c8e80547cf10 (diff)
downloadmetachan-d3507ae5b9d88a250b444c0e996fa07f84f6e3c5.tar.xz
metachan-d3507ae5b9d88a250b444c0e996fa07f84f6e3c5.zip
feat: Refactor anime and character handling
- Removed old GetAnimeEpisodes and GetAnimeEpisodesByMALID functions, replaced with a new implementation in episodes.go. - Added GetAnimeCharacters and GetAnimeCharacter functions to handle character retrieval. - Introduced CharacterAnimeAppearance entity to track character appearances in anime. - Updated repositories to manage character data and enrich character details. - Implemented enriched_at timestamp for both anime and characters to track data updates. - Added CharacterSync task to periodically enrich character data from the Jikan API. - Updated router to include new character-related endpoints.
Diffstat (limited to 'controllers')
-rw-r--r--controllers/anime.go328
-rw-r--r--controllers/episodes.go47
-rw-r--r--controllers/persona.go56
3 files changed, 103 insertions, 328 deletions
diff --git a/controllers/anime.go b/controllers/anime.go
index 85b1d72..2418c67 100644
--- a/controllers/anime.go
+++ b/controllers/anime.go
@@ -26,331 +26,3 @@ func GetAnime(c *fiber.Ctx) error {
return c.JSON(anime)
}
-
-func GetAnimeEpisodes(c *fiber.Ctx) error {
- id := meta.Request(c).MustHave().Param("id")
- provider := meta.Request(c).Default("mal").Query("provider")
-
- switch provider {
- case "mal", "anilist":
- default:
- return BadRequest(c, errors.New("invalid provider"))
- }
-
- episodes, err := repositories.GetAnimeEpisodes(enums.MappingType(provider), id)
- if err != nil {
- return NotFound(c, err)
- }
-
- return c.JSON(episodes)
-}
-
-// -- Old Code Below --
-
-// import (
-// "fmt"
-// "metachan/database"
-// "metachan/entities"
-// animeService "metachan/services/anime"
-// "metachan/utils/logger"
-// "metachan/utils/mappers"
-
-// "github.com/gofiber/fiber/v2"
-// )
-
-// // animeServiceInstance is a singleton instance of the anime service
-// var animeServiceInstance *animeService.Service
-
-// // getAnimeService returns the anime service instance, creating it if necessary
-// func getAnimeService() *animeService.Service {
-// if animeServiceInstance == nil {
-// animeServiceInstance = animeService.NewService()
-// }
-// return animeServiceInstance
-// }
-
-// // GetAnimeByMALID fetches anime details by MAL ID
-// func GetAnime(c *fiber.Ctx) error {
-// mapping, err := getAnimeMapping(c)
-// if err != nil {
-// return err
-// }
-
-// service := getAnimeService()
-// anime, err := service.GetAnimeDetails(mapping)
-// if err != nil {
-// logger.Log("Failed to fetch anime details: "+err.Error(), logger.LogOptions{
-// Level: logger.Error,
-// Prefix: "AnimeAPI",
-// })
-// return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
-// "error": "Failed to fetch anime details",
-// })
-// }
-
-// return c.JSON(anime)
-// }
-
-// // GetAnimeEpisodesByMALID fetches anime episodes by MAL ID
-// func GetAnimeEpisodes(c *fiber.Ctx) error {
-// mapping, err := getAnimeMapping(c)
-// if err != nil {
-// return err
-// }
-
-// service := getAnimeService()
-// anime, err := service.GetAnimeDetails(mapping)
-// if err != nil {
-// logger.Log("Failed to fetch anime episodes: "+err.Error(), logger.LogOptions{
-// Level: logger.Error,
-// Prefix: "AnimeAPI",
-// })
-// return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
-// "error": "Failed to fetch anime episodes",
-// })
-// }
-
-// // Return only the episodes data
-// return c.JSON(anime.Episodes)
-// }
-
-// // GetAnimeEpisode fetches a single episode by anime ID and episode ID
-// func GetAnimeEpisode(c *fiber.Ctx) error {
-// mapping, err := getAnimeMapping(c)
-// if err != nil {
-// return err
-// }
-
-// episodeID := c.Params("episodeId")
-// if episodeID == "" {
-// return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
-// "error": "Episode ID is required",
-// })
-// }
-
-// service := getAnimeService()
-// anime, err := service.GetAnimeDetails(mapping)
-// if err != nil {
-// logger.Log("Failed to fetch anime details: "+err.Error(), logger.LogOptions{
-// Level: logger.Error,
-// Prefix: "AnimeAPI",
-// })
-// return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
-// "error": "Failed to fetch anime details",
-// })
-// }
-
-// // Find the episode with matching ID
-// for i, episode := range anime.Episodes.Episodes {
-// if episode.ID == episodeID {
-// // Fetch streaming sources for this specific episode
-// episodeNumber := i + 1
-// streaming, err := service.GetEpisodeStreaming(anime.Titles.Romaji, episodeNumber, episode.ID, uint(anime.MALID))
-// if err != nil {
-// logger.Log("Failed to fetch streaming sources: "+err.Error(), logger.LogOptions{
-// Level: logger.Warn,
-// Prefix: "AnimeAPI",
-// })
-// // Continue without streaming data
-// } else {
-// episode.Streaming = streaming
-// }
-// return c.JSON(episode)
-// }
-// }
-
-// return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
-// "error": "Episode not found",
-// })
-// }
-
-// func GetAnimeCharacters(c *fiber.Ctx) error {
-// mapping, err := getAnimeMapping(c)
-// if err != nil {
-// return err
-// }
-
-// service := getAnimeService()
-// anime, err := service.GetAnimeDetails(mapping)
-// if err != nil {
-// logger.Log("Failed to fetch anime characters: "+err.Error(), logger.LogOptions{
-// Level: logger.Error,
-// Prefix: "AnimeAPI",
-// })
-// return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
-// "error": "Failed to fetch anime characters",
-// })
-// }
-
-// return c.JSON(anime.Characters)
-// }
-
-// func getAnimeMapping(c *fiber.Ctx) (*entities.AnimeMapping, error) {
-// isAnilist := c.Query("provider") == "anilist"
-// malID := c.Params("id")
-// if malID == "" {
-// return nil, c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
-// "error": "Query parameter MAL ID is required",
-// })
-// }
-
-// var mapping *entities.AnimeMapping
-// var err error
-// if isAnilist {
-// mapping, err = database.GetAnimeMappingViaAnilistID(mappers.ForceInt(malID))
-// } else {
-// mapping, err = database.GetAnimeMappingViaMALID(mappers.ForceInt(malID))
-// }
-// if err != nil || mapping.MAL == 0 {
-// return nil, c.Status(fiber.StatusNotFound).JSON(fiber.Map{
-// "error": "Anime mapping not found",
-// })
-// }
-
-// return mapping, nil
-// }
-
-// // GetGenres retrieves all genres from the database
-// func GetGenres(c *fiber.Ctx) error {
-// genres, err := database.GetAllGenres()
-// if err != nil {
-// logger.Log("Failed to get genres: "+err.Error(), logger.LogOptions{
-// Level: logger.Error,
-// Prefix: "Controller",
-// })
-// return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
-// "error": "Failed to retrieve genres",
-// })
-// }
-
-// return c.JSON(fiber.Map{
-// "genres": genres,
-// })
-// }
-
-// // GetAnimeByGenre retrieves paginated anime list for a specific genre
-// func GetAnimeByGenre(c *fiber.Ctx) error {
-// genreID := mappers.ForceInt(c.Params("id"))
-// page := mappers.ForceInt(c.Query("page", "1"))
-// limit := min(mappers.ForceInt(c.Query("limit", "12")), 100)
-// if limit < 1 {
-// limit = 25
-// }
-// if page < 1 {
-// page = 1
-// }
-
-// logger.Log(fmt.Sprintf("Fetching anime for genre %d, page %d, limit %d", genreID, page, limit), logger.LogOptions{
-// Level: logger.Debug,
-// Prefix: "GenreController",
-// })
-
-// service := getAnimeService()
-// animeList, pagination, err := service.GetAnimeByGenre(genreID, page, limit)
-// if err != nil {
-// logger.Log("Failed to fetch anime by genre: "+err.Error(), logger.LogOptions{
-// Level: logger.Error,
-// Prefix: "GenreController",
-// })
-// return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
-// "error": "Failed to retrieve anime for genre",
-// })
-// }
-
-// return c.JSON(fiber.Map{
-// "pagination": fiber.Map{
-// "current_page": pagination.CurrentPage,
-// "has_next_page": pagination.HasNextPage,
-// "last_visible_page": pagination.LastVisiblePage,
-// "total": pagination.Items.Total,
-// "per_page": pagination.Items.PerPage,
-// },
-// "data": animeList,
-// })
-// }
-
-// // GetProducers retrieves all producers with counts
-// func GetProducers(c *fiber.Ctx) error {
-// page := mappers.ForceInt(c.Query("page", "1"))
-// limit := min(mappers.ForceInt(c.Query("limit", "25")), 100)
-// if limit < 1 {
-// limit = 25
-// }
-// if page < 1 {
-// page = 1
-// }
-
-// producers, pagination, err := database.GetAllProducers(page, limit)
-// if err != nil {
-// logger.Log("Failed to get producers: "+err.Error(), logger.LogOptions{
-// Level: logger.Error,
-// Prefix: "Controller",
-// })
-// return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
-// "error": "Failed to retrieve producers",
-// })
-// }
-
-// return c.JSON(fiber.Map{
-// "pagination": pagination,
-// "producers": producers,
-// })
-// }
-
-// func GetProducer(c *fiber.Ctx) error {
-// producerID := mappers.ForceInt(c.Params("id"))
-
-// producer, err := database.GetProducerByID(producerID)
-// if err != nil {
-// logger.Log("Failed to get producer: "+err.Error(), logger.LogOptions{
-// Level: logger.Error,
-// Prefix: "Controller",
-// })
-// return c.Status(fiber.StatusNotFound).JSON(fiber.Map{
-// "error": "Producer not found",
-// })
-// }
-
-// return c.JSON(producer)
-// }
-
-// // GetAnimeByProducer retrieves paginated anime list for a specific producer
-// func GetAnimeByProducer(c *fiber.Ctx) error {
-// producerID := mappers.ForceInt(c.Params("id"))
-// page := mappers.ForceInt(c.Query("page", "1"))
-// limit := min(mappers.ForceInt(c.Query("limit", "12")), 100)
-// if limit < 1 {
-// limit = 25
-// }
-// if page < 1 {
-// page = 1
-// }
-
-// logger.Log(fmt.Sprintf("Fetching anime for producer %d, page %d, limit %d", producerID, page, limit), logger.LogOptions{
-// Level: logger.Debug,
-// Prefix: "ProducerController",
-// })
-
-// service := getAnimeService()
-// animeList, pagination, err := service.GetAnimeByProducer(producerID, page, limit)
-// if err != nil {
-// logger.Log("Failed to fetch anime by producer: "+err.Error(), logger.LogOptions{
-// Level: logger.Error,
-// Prefix: "ProducerController",
-// })
-// return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
-// "error": "Failed to retrieve anime for producer",
-// })
-// }
-
-// return c.JSON(fiber.Map{
-// "pagination": fiber.Map{
-// "current_page": pagination.CurrentPage,
-// "has_next_page": pagination.HasNextPage,
-// "last_visible_page": pagination.LastVisiblePage,
-// "total": pagination.Items.Total,
-// "per_page": pagination.Items.PerPage,
-// },
-// "data": animeList,
-// })
-// }
diff --git a/controllers/episodes.go b/controllers/episodes.go
new file mode 100644
index 0000000..a9ed32d
--- /dev/null
+++ b/controllers/episodes.go
@@ -0,0 +1,47 @@
+package controllers
+
+import (
+ "errors"
+ "metachan/enums"
+ "metachan/repositories"
+ "metachan/utils/meta"
+
+ "github.com/gofiber/fiber/v2"
+)
+
+func GetAnimeEpisodes(c *fiber.Ctx) error {
+ id := meta.Request(c).MustHave().Param("id")
+ provider := meta.Request(c).Default("mal").Query("provider")
+
+ switch provider {
+ case "mal", "anilist":
+ default:
+ return BadRequest(c, errors.New("invalid provider"))
+ }
+
+ episodes, err := repositories.GetAnimeEpisodes(enums.MappingType(provider), id)
+ if err != nil {
+ return NotFound(c, err)
+ }
+
+ return c.JSON(episodes)
+}
+
+func GetAnimeEpisode(c *fiber.Ctx) error {
+ id := meta.Request(c).MustHave().Param("id")
+ episodeID := meta.Request(c).MustHave().Param("episodeId")
+ provider := meta.Request(c).Default("mal").Query("provider")
+
+ switch provider {
+ case "mal", "anilist":
+ default:
+ return BadRequest(c, errors.New("invalid provider"))
+ }
+
+ episode, err := repositories.GetAnimeEpisode(enums.MappingType(provider), id, episodeID)
+ if err != nil {
+ return NotFound(c, err)
+ }
+
+ return c.JSON(episode)
+}
diff --git a/controllers/persona.go b/controllers/persona.go
new file mode 100644
index 0000000..d90157d
--- /dev/null
+++ b/controllers/persona.go
@@ -0,0 +1,56 @@
+package controllers
+
+import (
+ "errors"
+ "metachan/enums"
+ "metachan/repositories"
+ "metachan/utils/meta"
+ "strconv"
+
+ "github.com/gofiber/fiber/v2"
+)
+
+func GetAnimeCharacters(c *fiber.Ctx) error {
+ id := meta.Request(c).MustHave().Param("id")
+ provider := meta.Request(c).Default("mal").Query("provider")
+
+ switch provider {
+ case "mal", "anilist":
+ default:
+ return BadRequest(c, errors.New("invalid provider"))
+ }
+
+ characters, err := repositories.GetAnimeCharacters(enums.MappingType(provider), id)
+ if err != nil {
+ return NotFound(c, err)
+ }
+
+ return c.JSON(characters)
+}
+
+func GetAnimeCharacter(c *fiber.Ctx) error {
+ id := meta.Request(c).MustHave().Param("id")
+ characterID, ok := meta.Request(c).Param("characterId")
+ if !ok {
+ return BadRequest(c, errors.New("characterId is required"))
+ }
+ provider := meta.Request(c).Default("mal").Query("provider")
+
+ switch provider {
+ case "mal", "anilist":
+ default:
+ return BadRequest(c, errors.New("invalid provider"))
+ }
+
+ malID, err := strconv.Atoi(characterID)
+ if err != nil {
+ return BadRequest(c, errors.New("characterId must be a numeric MAL ID"))
+ }
+
+ character, err := repositories.GetAnimeCharacter(enums.MappingType(provider), id, malID)
+ if err != nil {
+ return NotFound(c, err)
+ }
+
+ return c.JSON(character)
+}