aboutsummaryrefslogtreecommitdiff
path: root/repositories
diff options
context:
space:
mode:
authorBobby <[email protected]>2026-02-25 10:42:51 +0530
committerBobby <[email protected]>2026-02-25 10:42:51 +0530
commitc18acfafee26d7d2508848135aa94a524f8dde06 (patch)
treee0b4d5e07f872d9252af6d73fb8b108e15a49f91 /repositories
parent2df69fab61b580b6b329db214ee0025a9d84958d (diff)
downloadmetachan-c18acfafee26d7d2508848135aa94a524f8dde06.tar.xz
metachan-c18acfafee26d7d2508848135aa94a524f8dde06.zip
Refactor anime update logic and task management
- Simplified title retrieval in AnimeUpdate and updateAnime functions. - Updated next airing checks to use new fields directly. - Removed unnecessary nil checks for titles in various functions. - Enhanced task management by eliminating redundant LastRun updates. - Improved dependency handling in triggerDependentTasks for better clarity and performance. - Streamlined Jikan API response structure by merging related fields. - Added StopRateLimiters function to rate limiter utilities for better control. - Refined episode title handling in TMDB and TVDB enrichment functions. - Introduced Stop method in MultiLimiter for graceful shutdown of rate limiters.
Diffstat (limited to 'repositories')
-rw-r--r--repositories/anime.go30
-rw-r--r--repositories/persona.go264
2 files changed, 158 insertions, 136 deletions
diff --git a/repositories/anime.go b/repositories/anime.go
index 4778f72..ae823c2 100644
--- a/repositories/anime.go
+++ b/repositories/anime.go
@@ -23,17 +23,9 @@ func GetAnime[T idType](maptype enums.MappingType, id T) (entities.Anime, error)
result := DB.
Preload("Mapping").
- Preload("Title").
- Preload("Images").
- Preload("Covers").
- Preload("Logos").
- Preload("Scores").
- Preload("AiringStatus").
- Preload("AiringStatus.From").
- Preload("AiringStatus.To").
- Preload("Broadcast").
- Preload("NextAiring").
Preload("Genres").
+ Preload("Themes").
+ Preload("Demographics").
Preload("Producers").
Preload("Producers.Image").
Preload("Producers.Titles").
@@ -47,19 +39,12 @@ func GetAnime[T idType](maptype enums.MappingType, id T) (entities.Anime, error)
Preload("Licensors.Titles").
Preload("Licensors.ExternalURLs").
Preload("Episodes").
- Preload("Episodes.Title").
Preload("Episodes.SkipTimes").
Preload("Episodes.StreamInfo").
Preload("Episodes.StreamInfo.SubSources").
Preload("Episodes.StreamInfo.DubSources").
Preload("Schedule").
Preload("Seasons").
- Preload("Seasons.Title").
- Preload("Seasons.Images").
- Preload("Seasons.Scores").
- Preload("Seasons.AiringStatus").
- Preload("Seasons.AiringStatus.From").
- Preload("Seasons.AiringStatus.To").
Where("mapping_id = ?", mapping.ID).
First(&anime)
@@ -110,12 +95,7 @@ func SaveAnimeEpisodes(animeID uint, episodes []entities.Episode) error {
var existing entities.Episode
if DB.Where("episode_id = ?", ep.EpisodeID).First(&existing).Error == nil {
ep.ID = existing.ID
- ep.TitleID = existing.TitleID
- DB.Model(ep).Omit("SkipTimes", "StreamInfo", "Title").Updates(ep)
- if ep.Title != nil && existing.TitleID != 0 {
- ep.Title.ID = existing.TitleID
- DB.Save(ep.Title)
- }
+ DB.Model(ep).Omit("SkipTimes", "StreamInfo").Updates(ep)
} else {
DB.Session(&gorm.Session{FullSaveAssociations: true}).
Omit("SkipTimes", "StreamInfo").
@@ -158,7 +138,6 @@ func GetAnimeEpisode[T idType](maptype enums.MappingType, id T, episodeID string
var episode entities.Episode
result := DB.
- Preload("Title").
Preload("SkipTimes").
Preload("StreamInfo").
Preload("StreamInfo.SubSources").
@@ -192,7 +171,6 @@ func GetAnimeEpisodes[T idType](maptype enums.MappingType, id T) ([]entities.Epi
var episodes []entities.Episode
result := DB.
- Preload("Title").
Preload("SkipTimes").
Preload("StreamInfo").
Preload("StreamInfo.SubSources").
@@ -240,9 +218,7 @@ func GetAiringAnime() ([]entities.Anime, error) {
result := DB.
Where("airing = ?", true).
- Preload("NextAiring").
Preload("Schedule").
- Preload("Title").
Find(&anime)
if result.Error != nil {
diff --git a/repositories/persona.go b/repositories/persona.go
index 1cb808c..1da6d29 100644
--- a/repositories/persona.go
+++ b/repositories/persona.go
@@ -36,43 +36,45 @@ func UpdateCharacterDetails(malID int, name, nameKanji, url, imageURL, about str
return err
}
- DB.Where("character_id = ?", char.ID).Delete(&entities.CharacterVoiceActor{})
- for _, cva := range voiceActors {
- va := cva.Person
- if va == nil {
- continue
- }
+ return DB.Transaction(func(tx *gorm.DB) error {
+ tx.Where("character_id = ?", char.ID).Delete(&entities.CharacterVoiceActor{})
+ for _, cva := range voiceActors {
+ va := cva.Person
+ if va == nil {
+ continue
+ }
- DB.Clauses(clause.OnConflict{
- Columns: []clause.Column{{Name: "mal_id"}},
- DoUpdates: clause.AssignmentColumns([]string{"url", "image", "name"}),
- }).Create(va)
- if va.ID == 0 {
- DB.Where("mal_id = ?", va.MALID).First(va)
- }
+ tx.Clauses(clause.OnConflict{
+ Columns: []clause.Column{{Name: "mal_id"}},
+ DoUpdates: clause.AssignmentColumns([]string{"url", "image", "name"}),
+ }).Create(va)
+ if va.ID == 0 {
+ tx.Where("mal_id = ?", va.MALID).First(va)
+ }
- DB.Clauses(clause.OnConflict{
- Columns: []clause.Column{{Name: "character_id"}, {Name: "person_id"}},
- DoUpdates: clause.AssignmentColumns([]string{"language"}),
- }).Create(&entities.CharacterVoiceActor{
- CharacterID: char.ID,
- PersonID: va.ID,
- Language: cva.Language,
- })
- }
+ tx.Clauses(clause.OnConflict{
+ Columns: []clause.Column{{Name: "character_id"}, {Name: "person_id"}},
+ DoUpdates: clause.AssignmentColumns([]string{"language"}),
+ }).Create(&entities.CharacterVoiceActor{
+ CharacterID: char.ID,
+ PersonID: va.ID,
+ Language: cva.Language,
+ })
+ }
- DB.Where("character_id = ?", char.ID).Delete(&entities.CharacterAnimeAppearance{})
- for i := range animeAppearances {
- animeAppearances[i].CharacterID = char.ID
- }
- if len(animeAppearances) > 0 {
- DB.Clauses(clause.OnConflict{
- Columns: []clause.Column{{Name: "character_id"}, {Name: "anime_mal_id"}},
- DoUpdates: clause.AssignmentColumns([]string{"title", "url", "image_url", "role"}),
- }).Create(&animeAppearances)
- }
+ tx.Where("character_id = ?", char.ID).Delete(&entities.CharacterAnimeAppearance{})
+ for i := range animeAppearances {
+ animeAppearances[i].CharacterID = char.ID
+ }
+ if len(animeAppearances) > 0 {
+ tx.Clauses(clause.OnConflict{
+ Columns: []clause.Column{{Name: "character_id"}, {Name: "anime_mal_id"}},
+ DoUpdates: clause.AssignmentColumns([]string{"title", "url", "image_url", "role"}),
+ }).Create(&animeAppearances)
+ }
- return nil
+ return nil
+ })
}
func GetAnimeCharacters[T idType](maptype enums.MappingType, id T) ([]entities.Character, error) {
@@ -98,15 +100,31 @@ func GetAnimeCharacters[T idType](maptype enums.MappingType, id T) ([]entities.C
Where("anime_id = ?", anime.ID).
Scan(&rows)
+ if len(rows) == 0 {
+ return []entities.Character{}, nil
+ }
+
+ charIDs := make([]uint, len(rows))
+ roleMap := make(map[uint]string, len(rows))
+ for i, row := range rows {
+ charIDs[i] = row.CharacterID
+ roleMap[row.CharacterID] = row.Role
+ }
+
var characters []entities.Character
- for _, row := range rows {
- var char entities.Character
- if err := DB.First(&char, row.CharacterID).Error; err != nil {
- continue
- }
- DB.Preload("Person").Where("character_id = ?", char.ID).Find(&char.VoiceActors)
- char.Role = row.Role
- characters = append(characters, char)
+ DB.Where("id IN ?", charIDs).Find(&characters)
+
+ var voiceActors []entities.CharacterVoiceActor
+ DB.Preload("Person").Where("character_id IN ?", charIDs).Find(&voiceActors)
+
+ voiceActorsByCharacterID := make(map[uint][]entities.CharacterVoiceActor)
+ for _, voiceActor := range voiceActors {
+ voiceActorsByCharacterID[voiceActor.CharacterID] = append(voiceActorsByCharacterID[voiceActor.CharacterID], voiceActor)
+ }
+
+ for i := range characters {
+ characters[i].Role = roleMap[characters[i].ID]
+ characters[i].VoiceActors = voiceActorsByCharacterID[characters[i].ID]
}
return characters, nil
@@ -159,17 +177,34 @@ func loadAnimeCharacters(anime *entities.Anime) {
Where("anime_id = ?", anime.ID).
Scan(&rows)
- for _, row := range rows {
- var char entities.Character
- if err := DB.First(&char, row.CharacterID).Error; err != nil {
- continue
- }
- DB.Preload("Person").
- Where("character_id = ?", char.ID).
- Find(&char.VoiceActors)
- char.Role = row.Role
- anime.Characters = append(anime.Characters, char)
+ if len(rows) == 0 {
+ return
}
+
+ charIDs := make([]uint, len(rows))
+ roleMap := make(map[uint]string, len(rows))
+ for i, row := range rows {
+ charIDs[i] = row.CharacterID
+ roleMap[row.CharacterID] = row.Role
+ }
+
+ var characters []entities.Character
+ DB.Where("id IN ?", charIDs).Find(&characters)
+
+ var voiceActors []entities.CharacterVoiceActor
+ DB.Preload("Person").Where("character_id IN ?", charIDs).Find(&voiceActors)
+
+ voiceActorsByCharacterID := make(map[uint][]entities.CharacterVoiceActor)
+ for _, voiceActor := range voiceActors {
+ voiceActorsByCharacterID[voiceActor.CharacterID] = append(voiceActorsByCharacterID[voiceActor.CharacterID], voiceActor)
+ }
+
+ for i := range characters {
+ characters[i].Role = roleMap[characters[i].ID]
+ characters[i].VoiceActors = voiceActorsByCharacterID[characters[i].ID]
+ }
+
+ anime.Characters = characters
}
func SaveAnimeCharacters(animeID uint, characters []entities.Character) error {
@@ -279,40 +314,48 @@ func UpdatePersonDetails(
return err
}
- DB.Where("person_id = ?", p.ID).Delete(&entities.PersonVoiceRole{})
- for i := range voiceRoles {
- voiceRoles[i].PersonID = p.ID
- }
- if len(voiceRoles) > 0 {
- DB.Clauses(clause.OnConflict{
- Columns: []clause.Column{{Name: "person_id"}, {Name: "anime_mal_id"}, {Name: "character_mal_id"}},
- DoUpdates: clause.AssignmentColumns([]string{"role", "anime_title", "anime_url", "anime_image_url", "character_name", "character_url", "character_image_url"}),
- }).Create(&voiceRoles)
- }
+ return DB.Transaction(func(tx *gorm.DB) error {
+ tx.Where("person_id = ?", p.ID).Delete(&entities.PersonVoiceRole{})
+ for i := range voiceRoles {
+ voiceRoles[i].PersonID = p.ID
+ }
+ if len(voiceRoles) > 0 {
+ if err := tx.Clauses(clause.OnConflict{
+ Columns: []clause.Column{{Name: "person_id"}, {Name: "anime_mal_id"}, {Name: "character_mal_id"}},
+ DoUpdates: clause.AssignmentColumns([]string{"role", "anime_title", "anime_url", "anime_image_url", "character_name", "character_url", "character_image_url"}),
+ }).Create(&voiceRoles).Error; err != nil {
+ return err
+ }
+ }
- DB.Where("person_id = ?", p.ID).Delete(&entities.PersonAnimeCredit{})
- for i := range animeCredits {
- animeCredits[i].PersonID = p.ID
- }
- if len(animeCredits) > 0 {
- DB.Clauses(clause.OnConflict{
- Columns: []clause.Column{{Name: "person_id"}, {Name: "anime_mal_id"}},
- DoUpdates: clause.AssignmentColumns([]string{"position", "anime_title", "anime_url", "anime_image_url"}),
- }).Create(&animeCredits)
- }
+ tx.Where("person_id = ?", p.ID).Delete(&entities.PersonAnimeCredit{})
+ for i := range animeCredits {
+ animeCredits[i].PersonID = p.ID
+ }
+ if len(animeCredits) > 0 {
+ if err := tx.Clauses(clause.OnConflict{
+ Columns: []clause.Column{{Name: "person_id"}, {Name: "anime_mal_id"}},
+ DoUpdates: clause.AssignmentColumns([]string{"position", "anime_title", "anime_url", "anime_image_url"}),
+ }).Create(&animeCredits).Error; err != nil {
+ return err
+ }
+ }
- DB.Where("person_id = ?", p.ID).Delete(&entities.PersonMangaCredit{})
- for i := range mangaCredits {
- mangaCredits[i].PersonID = p.ID
- }
- if len(mangaCredits) > 0 {
- DB.Clauses(clause.OnConflict{
- Columns: []clause.Column{{Name: "person_id"}, {Name: "manga_mal_id"}},
- DoUpdates: clause.AssignmentColumns([]string{"position", "manga_title", "manga_url", "manga_image_url"}),
- }).Create(&mangaCredits)
- }
+ tx.Where("person_id = ?", p.ID).Delete(&entities.PersonMangaCredit{})
+ for i := range mangaCredits {
+ mangaCredits[i].PersonID = p.ID
+ }
+ if len(mangaCredits) > 0 {
+ if err := tx.Clauses(clause.OnConflict{
+ Columns: []clause.Column{{Name: "person_id"}, {Name: "manga_mal_id"}},
+ DoUpdates: clause.AssignmentColumns([]string{"position", "manga_title", "manga_url", "manga_image_url"}),
+ }).Create(&mangaCredits).Error; err != nil {
+ return err
+ }
+ }
- return nil
+ return nil
+ })
}
func SetPersonEnriched(malID int) error {
@@ -334,46 +377,49 @@ func GetAnimePeople[T idType](maptype enums.MappingType, id T) ([]entities.Perso
return nil, errors.New("anime not found")
}
- var charRows []struct {
- CharacterID uint
- }
+ var charIDs []uint
DB.Table("anime_characters").
Select("character_id").
Where("anime_id = ?", anime.ID).
- Scan(&charRows)
+ Pluck("character_id", &charIDs)
+
+ if len(charIDs) == 0 {
+ return []entities.Person{}, nil
+ }
+
+ var characters []entities.Character
+ DB.Where("id IN ?", charIDs).Find(&characters)
+
+ characterByID := make(map[uint]*entities.Character, len(characters))
+ for i := range characters {
+ characterByID[characters[i].ID] = &characters[i]
+ }
+
+ var characterVoiceActors []entities.CharacterVoiceActor
+ DB.Preload("Person").Where("character_id IN ?", charIDs).Find(&characterVoiceActors)
personMap := make(map[uint]*entities.Person)
- personChars := make(map[uint][]entities.PersonCharacterEntry)
+ personCharacters := make(map[uint][]entities.PersonCharacterEntry)
- for _, row := range charRows {
- var char entities.Character
- if err := DB.First(&char, row.CharacterID).Error; err != nil {
+ for _, voiceActorEntry := range characterVoiceActors {
+ if voiceActorEntry.Person == nil {
continue
}
-
- var cvas []entities.CharacterVoiceActor
- DB.Preload("Person").Where("character_id = ?", char.ID).Find(&cvas)
-
- for _, cva := range cvas {
- if cva.Person == nil {
- continue
- }
- pID := cva.PersonID
- if _, exists := personMap[pID]; !exists {
- personMap[pID] = cva.Person
- }
- charCopy := char
- personChars[pID] = append(personChars[pID], entities.PersonCharacterEntry{
- Character: &charCopy,
- Language: cva.Language,
+ if _, exists := personMap[voiceActorEntry.PersonID]; !exists {
+ personMap[voiceActorEntry.PersonID] = voiceActorEntry.Person
+ }
+ if character, ok := characterByID[voiceActorEntry.CharacterID]; ok {
+ personCharacters[voiceActorEntry.PersonID] = append(personCharacters[voiceActorEntry.PersonID], entities.PersonCharacterEntry{
+ Character: character,
+ Language: voiceActorEntry.Language,
})
}
}
result := make([]entities.Person, 0, len(personMap))
- for pID, p := range personMap {
- p.Characters = personChars[pID]
- result = append(result, *p)
+ for personID, person := range personMap {
+ person.Characters = personCharacters[personID]
+ result = append(result, *person)
}
return result, nil
}