Files
seanime-docker/seanime-2.9.10/internal/database/db/media_filler.go
2025-09-20 14:08:38 +01:00

183 lines
3.9 KiB
Go

package db
import (
"github.com/goccy/go-json"
"github.com/samber/mo"
"seanime/internal/api/filler"
"seanime/internal/database/models"
"time"
)
type MediaFillerItem struct {
DbId uint `json:"dbId"`
Provider string `json:"provider"`
Slug string `json:"slug"`
MediaId int `json:"mediaId"`
LastFetchedAt time.Time `json:"lastFetchedAt"`
FillerEpisodes []string `json:"fillerEpisodes"`
}
// GetCachedMediaFillers will return all the media fillers (cache-first).
// If the cache is empty, it will fetch the media fillers from the database.
func (db *Database) GetCachedMediaFillers() (map[int]*MediaFillerItem, error) {
if db.CurrMediaFillers.IsPresent() {
return db.CurrMediaFillers.MustGet(), nil
}
var res []*models.MediaFiller
err := db.gormdb.Find(&res).Error
if err != nil {
return nil, err
}
// Unmarshal the media fillers
mediaFillers := make(map[int]*MediaFillerItem)
for _, mf := range res {
var fillerData filler.Data
if err := json.Unmarshal(mf.Data, &fillerData); err != nil {
return nil, err
}
// Get the filler episodes
var fillerEpisodes []string
if fillerData.FillerEpisodes != nil || len(fillerData.FillerEpisodes) > 0 {
fillerEpisodes = fillerData.FillerEpisodes
}
mediaFillers[mf.MediaID] = &MediaFillerItem{
DbId: mf.ID,
Provider: mf.Provider,
MediaId: mf.MediaID,
Slug: mf.Slug,
LastFetchedAt: mf.LastFetchedAt,
FillerEpisodes: fillerEpisodes,
}
}
// Cache the media fillers
db.CurrMediaFillers = mo.Some(mediaFillers)
return db.CurrMediaFillers.MustGet(), nil
}
func (db *Database) GetMediaFillerItem(mediaId int) (*MediaFillerItem, bool) {
mediaFillers, err := db.GetCachedMediaFillers()
if err != nil {
return nil, false
}
item, ok := mediaFillers[mediaId]
return item, ok
}
func (db *Database) InsertMediaFiller(
provider string,
mediaId int,
slug string,
lastFetchedAt time.Time,
fillerEpisodes []string,
) error {
// Marshal the filler data
fillerData := filler.Data{
FillerEpisodes: fillerEpisodes,
}
fillerDataBytes, err := json.Marshal(fillerData)
if err != nil {
return err
}
// Delete the existing media filler
_ = db.DeleteMediaFiller(mediaId)
// Save the media filler
err = db.gormdb.Create(&models.MediaFiller{
Provider: provider,
MediaID: mediaId,
Slug: slug,
LastFetchedAt: lastFetchedAt,
Data: fillerDataBytes,
}).Error
if err != nil {
return err
}
// Update the cache
db.CurrMediaFillers = mo.None[map[int]*MediaFillerItem]()
return nil
}
// SaveCachedMediaFillerItems will save the cached media filler items in the database.
// Call this function after editing the cached media filler items.
func (db *Database) SaveCachedMediaFillerItems() error {
if db.CurrMediaFillers.IsAbsent() {
return nil
}
mediaFillers, err := db.GetCachedMediaFillers()
if err != nil {
return err
}
for _, mf := range mediaFillers {
if len(mf.FillerEpisodes) == 0 {
continue
}
// Marshal the filler data
fillerData := filler.Data{
FillerEpisodes: mf.FillerEpisodes,
}
fillerDataBytes, err := json.Marshal(fillerData)
if err != nil {
return err
}
// Save the media filler
err = db.gormdb.Model(&models.MediaFiller{}).
Where("id = ?", mf.DbId).
Updates(map[string]interface{}{
"last_fetched_at": mf.LastFetchedAt,
"data": fillerDataBytes,
}).Error
if err != nil {
return err
}
}
// Update the cache
db.CurrMediaFillers = mo.None[map[int]*MediaFillerItem]()
return nil
}
func (db *Database) DeleteMediaFiller(mediaId int) error {
mediaFillers, err := db.GetCachedMediaFillers()
if err != nil {
return err
}
item, ok := mediaFillers[mediaId]
if !ok {
return nil
}
err = db.gormdb.Delete(&models.MediaFiller{}, item.DbId).Error
if err != nil {
return err
}
// Update the cache
db.CurrMediaFillers = mo.None[map[int]*MediaFillerItem]()
return nil
}