node build fixed
This commit is contained in:
7
seanime-2.9.10/internal/database/db/README.md
Normal file
7
seanime-2.9.10/internal/database/db/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# db
|
||||
|
||||
Should only import `models` internal package.
|
||||
|
||||
### 🚫 Do not
|
||||
|
||||
- Do not define **models** here.
|
||||
59
seanime-2.9.10/internal/database/db/account.go
Normal file
59
seanime-2.9.10/internal/database/db/account.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"seanime/internal/database/models"
|
||||
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
var accountCache *models.Account
|
||||
|
||||
func (db *Database) UpsertAccount(acc *models.Account) (*models.Account, error) {
|
||||
err := db.gormdb.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "id"}},
|
||||
UpdateAll: true,
|
||||
}).Create(acc).Error
|
||||
|
||||
if err != nil {
|
||||
db.Logger.Error().Err(err).Msg("Failed to save account in the database")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if acc.Username != "" {
|
||||
accountCache = acc
|
||||
} else {
|
||||
accountCache = nil
|
||||
}
|
||||
|
||||
return acc, nil
|
||||
}
|
||||
|
||||
func (db *Database) GetAccount() (*models.Account, error) {
|
||||
|
||||
if accountCache != nil {
|
||||
return accountCache, nil
|
||||
}
|
||||
|
||||
var acc models.Account
|
||||
err := db.gormdb.Last(&acc).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if acc.Username == "" || acc.Token == "" || acc.Viewer == nil {
|
||||
return nil, errors.New("account not found")
|
||||
}
|
||||
|
||||
accountCache = &acc
|
||||
|
||||
return &acc, err
|
||||
}
|
||||
|
||||
// GetAnilistToken retrieves the AniList token from the account or returns an empty string
|
||||
func (db *Database) GetAnilistToken() string {
|
||||
acc, err := db.GetAccount()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return acc.Token
|
||||
}
|
||||
57
seanime-2.9.10/internal/database/db/autodownloader_item.go
Normal file
57
seanime-2.9.10/internal/database/db/autodownloader_item.go
Normal file
@@ -0,0 +1,57 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"seanime/internal/database/models"
|
||||
)
|
||||
|
||||
func (db *Database) GetAutoDownloaderItems() ([]*models.AutoDownloaderItem, error) {
|
||||
var res []*models.AutoDownloaderItem
|
||||
err := db.gormdb.Find(&res).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (db *Database) GetAutoDownloaderItem(id uint) (*models.AutoDownloaderItem, error) {
|
||||
var res models.AutoDownloaderItem
|
||||
err := db.gormdb.First(&res, id).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func (db *Database) GetAutoDownloaderItemByMediaId(mId int) ([]*models.AutoDownloaderItem, error) {
|
||||
var res []*models.AutoDownloaderItem
|
||||
err := db.gormdb.Where("media_id = ?", mId).Find(&res).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (db *Database) InsertAutoDownloaderItem(item *models.AutoDownloaderItem) error {
|
||||
err := db.gormdb.Create(item).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) DeleteAutoDownloaderItem(id uint) error {
|
||||
return db.gormdb.Delete(&models.AutoDownloaderItem{}, id).Error
|
||||
}
|
||||
|
||||
// DeleteDownloadedAutoDownloaderItems will delete all the downloaded queued items from the database.
|
||||
func (db *Database) DeleteDownloadedAutoDownloaderItems() error {
|
||||
return db.gormdb.Where("downloaded = ?", true).Delete(&models.AutoDownloaderItem{}).Error
|
||||
}
|
||||
|
||||
func (db *Database) UpdateAutoDownloaderItem(id uint, item *models.AutoDownloaderItem) error {
|
||||
// Save the data
|
||||
return db.gormdb.Model(&models.AutoDownloaderItem{}).Where("id = ?", id).Updates(item).Error
|
||||
}
|
||||
135
seanime-2.9.10/internal/database/db/chapter_downloader_queue.go
Normal file
135
seanime-2.9.10/internal/database/db/chapter_downloader_queue.go
Normal file
@@ -0,0 +1,135 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"gorm.io/gorm"
|
||||
"seanime/internal/database/models"
|
||||
)
|
||||
|
||||
func (db *Database) GetChapterDownloadQueue() ([]*models.ChapterDownloadQueueItem, error) {
|
||||
var res []*models.ChapterDownloadQueueItem
|
||||
err := db.gormdb.Find(&res).Error
|
||||
if err != nil {
|
||||
db.Logger.Error().Err(err).Msg("db: Failed to get chapter download queue")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (db *Database) GetNextChapterDownloadQueueItem() (*models.ChapterDownloadQueueItem, error) {
|
||||
var res models.ChapterDownloadQueueItem
|
||||
err := db.gormdb.Where("status = ?", "not_started").First(&res).Error
|
||||
if err != nil {
|
||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
db.Logger.Error().Err(err).Msg("db: Failed to get next chapter download queue item")
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func (db *Database) DequeueChapterDownloadQueueItem() (*models.ChapterDownloadQueueItem, error) {
|
||||
// Pop the first item from the queue
|
||||
var res models.ChapterDownloadQueueItem
|
||||
err := db.gormdb.Where("status = ?", "downloading").First(&res).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = db.gormdb.Delete(&res).Error
|
||||
if err != nil {
|
||||
db.Logger.Error().Err(err).Msg("db: Failed to delete chapter download queue item")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func (db *Database) InsertChapterDownloadQueueItem(item *models.ChapterDownloadQueueItem) error {
|
||||
|
||||
// Check if the item already exists
|
||||
var existingItem models.ChapterDownloadQueueItem
|
||||
err := db.gormdb.Where("provider = ? AND media_id = ? AND chapter_id = ?", item.Provider, item.MediaID, item.ChapterID).First(&existingItem).Error
|
||||
if err == nil {
|
||||
db.Logger.Debug().Msg("db: Chapter download queue item already exists")
|
||||
return errors.New("chapter is already in the download queue")
|
||||
}
|
||||
|
||||
if item.ChapterID == "" {
|
||||
return errors.New("chapter ID is empty")
|
||||
}
|
||||
if item.Provider == "" {
|
||||
return errors.New("provider is empty")
|
||||
}
|
||||
if item.MediaID == 0 {
|
||||
return errors.New("media ID is empty")
|
||||
}
|
||||
if item.ChapterNumber == "" {
|
||||
return errors.New("chapter number is empty")
|
||||
}
|
||||
|
||||
err = db.gormdb.Create(item).Error
|
||||
if err != nil {
|
||||
db.Logger.Error().Err(err).Msg("db: Failed to insert chapter download queue item")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) UpdateChapterDownloadQueueItemStatus(provider string, mId int, chapterId string, status string) error {
|
||||
err := db.gormdb.Model(&models.ChapterDownloadQueueItem{}).
|
||||
Where("provider = ? AND media_id = ? AND chapter_id = ?", provider, mId, chapterId).
|
||||
Update("status", status).Error
|
||||
if err != nil {
|
||||
db.Logger.Error().Err(err).Msg("db: Failed to update chapter download queue item status")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) GetMediaQueuedChapters(mediaId int) ([]*models.ChapterDownloadQueueItem, error) {
|
||||
var res []*models.ChapterDownloadQueueItem
|
||||
err := db.gormdb.Where("media_id = ?", mediaId).Find(&res).Error
|
||||
if err != nil {
|
||||
db.Logger.Error().Err(err).Msg("db: Failed to get media queued chapters")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (db *Database) ClearAllChapterDownloadQueueItems() error {
|
||||
err := db.gormdb.
|
||||
Where("status = ? OR status = ? OR status = ?", "not_started", "downloading", "errored").
|
||||
Delete(&models.ChapterDownloadQueueItem{}).
|
||||
Error
|
||||
if err != nil {
|
||||
db.Logger.Error().Err(err).Msg("db: Failed to clear all chapter download queue items")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) ResetErroredChapterDownloadQueueItems() error {
|
||||
err := db.gormdb.Model(&models.ChapterDownloadQueueItem{}).
|
||||
Where("status = ?", "errored").
|
||||
Update("status", "not_started").Error
|
||||
if err != nil {
|
||||
db.Logger.Error().Err(err).Msg("db: Failed to reset errored chapter download queue items")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) ResetDownloadingChapterDownloadQueueItems() error {
|
||||
err := db.gormdb.Model(&models.ChapterDownloadQueueItem{}).
|
||||
Where("status = ?", "downloading").
|
||||
Update("status", "not_started").Error
|
||||
if err != nil {
|
||||
db.Logger.Error().Err(err).Msg("db: Failed to reset downloading chapter download queue items")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
102
seanime-2.9.10/internal/database/db/db.go
Normal file
102
seanime-2.9.10/internal/database/db/db.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"seanime/internal/database/models"
|
||||
"time"
|
||||
|
||||
"github.com/glebarez/sqlite"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/samber/mo"
|
||||
"gorm.io/gorm"
|
||||
gormlogger "gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
type Database struct {
|
||||
gormdb *gorm.DB
|
||||
Logger *zerolog.Logger
|
||||
CurrMediaFillers mo.Option[map[int]*MediaFillerItem]
|
||||
}
|
||||
|
||||
func (db *Database) Gorm() *gorm.DB {
|
||||
return db.gormdb
|
||||
}
|
||||
|
||||
func NewDatabase(appDataDir, dbName string, logger *zerolog.Logger) (*Database, error) {
|
||||
|
||||
// Set the SQLite database path
|
||||
var sqlitePath string
|
||||
if os.Getenv("TEST_ENV") == "true" {
|
||||
sqlitePath = ":memory:"
|
||||
} else {
|
||||
sqlitePath = filepath.Join(appDataDir, dbName+".db")
|
||||
}
|
||||
|
||||
// Connect to the SQLite database
|
||||
db, err := gorm.Open(sqlite.Open(sqlitePath), &gorm.Config{
|
||||
Logger: gormlogger.New(
|
||||
log.New(os.Stdout, "\r\n", log.LstdFlags),
|
||||
gormlogger.Config{
|
||||
SlowThreshold: time.Second,
|
||||
LogLevel: gormlogger.Error,
|
||||
IgnoreRecordNotFoundError: true,
|
||||
ParameterizedQueries: false,
|
||||
Colorful: true,
|
||||
},
|
||||
),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Migrate tables
|
||||
err = migrateTables(db)
|
||||
if err != nil {
|
||||
logger.Fatal().Err(err).Msg("db: Failed to perform auto migration")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logger.Info().Str("name", fmt.Sprintf("%s.db", dbName)).Msg("db: Database instantiated")
|
||||
|
||||
return &Database{
|
||||
gormdb: db,
|
||||
Logger: logger,
|
||||
CurrMediaFillers: mo.None[map[int]*MediaFillerItem](),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// MigrateTables performs auto migration on the database
|
||||
func migrateTables(db *gorm.DB) error {
|
||||
err := db.AutoMigrate(
|
||||
&models.LocalFiles{},
|
||||
&models.Settings{},
|
||||
&models.Account{},
|
||||
&models.Mal{},
|
||||
&models.ScanSummary{},
|
||||
&models.AutoDownloaderRule{},
|
||||
&models.AutoDownloaderItem{},
|
||||
&models.SilencedMediaEntry{},
|
||||
&models.Theme{},
|
||||
&models.PlaylistEntry{},
|
||||
&models.ChapterDownloadQueueItem{},
|
||||
&models.TorrentstreamSettings{},
|
||||
&models.TorrentstreamHistory{},
|
||||
&models.MediastreamSettings{},
|
||||
&models.MediaFiller{},
|
||||
&models.MangaMapping{},
|
||||
&models.OnlinestreamMapping{},
|
||||
&models.DebridSettings{},
|
||||
&models.DebridTorrentItem{},
|
||||
&models.PluginData{},
|
||||
//&models.MangaChapterContainer{},
|
||||
)
|
||||
if err != nil {
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
56
seanime-2.9.10/internal/database/db/debrid_torrent_item.go
Normal file
56
seanime-2.9.10/internal/database/db/debrid_torrent_item.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"seanime/internal/database/models"
|
||||
)
|
||||
|
||||
func (db *Database) GetDebridTorrentItems() ([]*models.DebridTorrentItem, error) {
|
||||
var res []*models.DebridTorrentItem
|
||||
err := db.gormdb.Find(&res).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (db *Database) GetDebridTorrentItemByDbId(dbId uint) (*models.DebridTorrentItem, error) {
|
||||
var res models.DebridTorrentItem
|
||||
err := db.gormdb.First(&res, dbId).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func (db *Database) GetDebridTorrentItemByTorrentItemId(tId string) (*models.DebridTorrentItem, error) {
|
||||
var res *models.DebridTorrentItem
|
||||
err := db.gormdb.Where("torrent_item_id = ?", tId).First(&res).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (db *Database) InsertDebridTorrentItem(item *models.DebridTorrentItem) error {
|
||||
err := db.gormdb.Create(item).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) DeleteDebridTorrentItemByDbId(dbId uint) error {
|
||||
return db.gormdb.Delete(&models.DebridTorrentItem{}, dbId).Error
|
||||
}
|
||||
|
||||
func (db *Database) DeleteDebridTorrentItemByTorrentItemId(tId string) error {
|
||||
return db.gormdb.Where("torrent_item_id = ?", tId).Delete(&models.DebridTorrentItem{}).Error
|
||||
}
|
||||
|
||||
func (db *Database) UpdateDebridTorrentItemByDbId(dbId uint, item *models.DebridTorrentItem) error {
|
||||
// Save the data
|
||||
return db.gormdb.Model(&models.DebridTorrentItem{}).Where("id = ?", dbId).Updates(item).Error
|
||||
}
|
||||
51
seanime-2.9.10/internal/database/db/localfiles.go
Normal file
51
seanime-2.9.10/internal/database/db/localfiles.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"seanime/internal/database/models"
|
||||
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
// TrimLocalFileEntries will trim the local file entries if there are more than 10 entries.
|
||||
// This is run in a goroutine.
|
||||
func (db *Database) TrimLocalFileEntries() {
|
||||
go func() {
|
||||
var count int64
|
||||
err := db.gormdb.Model(&models.LocalFiles{}).Count(&count).Error
|
||||
if err != nil {
|
||||
db.Logger.Error().Err(err).Msg("database: Failed to count local file entries")
|
||||
return
|
||||
}
|
||||
if count > 10 {
|
||||
// Leave 5 entries
|
||||
err = db.gormdb.Delete(&models.LocalFiles{}, "id IN (SELECT id FROM local_files ORDER BY id ASC LIMIT ?)", count-5).Error
|
||||
if err != nil {
|
||||
db.Logger.Error().Err(err).Msg("database: Failed to delete old local file entries")
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
func (db *Database) UpsertLocalFiles(lfs *models.LocalFiles) (*models.LocalFiles, error) {
|
||||
err := db.gormdb.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "id"}},
|
||||
UpdateAll: true,
|
||||
}).Create(lfs).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return lfs, nil
|
||||
}
|
||||
|
||||
func (db *Database) InsertLocalFiles(lfs *models.LocalFiles) (*models.LocalFiles, error) {
|
||||
err := db.gormdb.Create(lfs).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return lfs, nil
|
||||
}
|
||||
50
seanime-2.9.10/internal/database/db/mal.go
Normal file
50
seanime-2.9.10/internal/database/db/mal.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
"seanime/internal/database/models"
|
||||
)
|
||||
|
||||
func (db *Database) GetMalInfo() (*models.Mal, error) {
|
||||
// Get the first entry
|
||||
var res models.Mal
|
||||
err := db.gormdb.First(&res, 1).Error
|
||||
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, errors.New("MAL not connected")
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func (db *Database) UpsertMalInfo(info *models.Mal) (*models.Mal, error) {
|
||||
err := db.gormdb.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "id"}},
|
||||
UpdateAll: true,
|
||||
}).Create(info).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func (db *Database) InsertMalInfo(info *models.Mal) (*models.Mal, error) {
|
||||
err := db.gormdb.Create(info).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func (db *Database) DeleteMalInfo() error {
|
||||
err := db.gormdb.Delete(&models.Mal{}, 1).Error
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
102
seanime-2.9.10/internal/database/db/manga.go
Normal file
102
seanime-2.9.10/internal/database/db/manga.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"seanime/internal/database/models"
|
||||
"seanime/internal/util/result"
|
||||
)
|
||||
|
||||
var mangaMappingCache = result.NewResultMap[string, *models.MangaMapping]()
|
||||
|
||||
func formatMangaMappingCacheKey(provider string, mediaId int) string {
|
||||
return fmt.Sprintf("%s$%d", provider, mediaId)
|
||||
}
|
||||
|
||||
func (db *Database) GetMangaMapping(provider string, mediaId int) (*models.MangaMapping, bool) {
|
||||
|
||||
if res, ok := mangaMappingCache.Get(formatMangaMappingCacheKey(provider, mediaId)); ok {
|
||||
return res, true
|
||||
}
|
||||
|
||||
var res models.MangaMapping
|
||||
err := db.gormdb.Where("provider = ? AND media_id = ?", provider, mediaId).First(&res).Error
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
mangaMappingCache.Set(formatMangaMappingCacheKey(provider, mediaId), &res)
|
||||
|
||||
return &res, true
|
||||
}
|
||||
|
||||
func (db *Database) InsertMangaMapping(provider string, mediaId int, mangaId string) error {
|
||||
mapping := models.MangaMapping{
|
||||
Provider: provider,
|
||||
MediaID: mediaId,
|
||||
MangaID: mangaId,
|
||||
}
|
||||
|
||||
mangaMappingCache.Set(formatMangaMappingCacheKey(provider, mediaId), &mapping)
|
||||
|
||||
return db.gormdb.Save(&mapping).Error
|
||||
}
|
||||
|
||||
func (db *Database) DeleteMangaMapping(provider string, mediaId int) error {
|
||||
err := db.gormdb.Where("provider = ? AND media_id = ?", provider, mediaId).Delete(&models.MangaMapping{}).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mangaMappingCache.Delete(formatMangaMappingCacheKey(provider, mediaId))
|
||||
return nil
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var mangaChapterContainerCache = result.NewResultMap[string, *models.MangaChapterContainer]()
|
||||
|
||||
func formatMangaChapterContainerCacheKey(provider string, mediaId int, chapterId string) string {
|
||||
return fmt.Sprintf("%s$%d$%s", provider, mediaId, chapterId)
|
||||
}
|
||||
|
||||
func (db *Database) GetMangaChapterContainer(provider string, mediaId int, chapterId string) (*models.MangaChapterContainer, bool) {
|
||||
|
||||
if res, ok := mangaChapterContainerCache.Get(formatMangaChapterContainerCacheKey(provider, mediaId, chapterId)); ok {
|
||||
return res, true
|
||||
}
|
||||
|
||||
var res models.MangaChapterContainer
|
||||
err := db.gormdb.Where("provider = ? AND media_id = ? AND chapter_id = ?", provider, mediaId, chapterId).First(&res).Error
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
mangaChapterContainerCache.Set(formatMangaChapterContainerCacheKey(provider, mediaId, chapterId), &res)
|
||||
|
||||
return &res, true
|
||||
}
|
||||
|
||||
func (db *Database) InsertMangaChapterContainer(provider string, mediaId int, chapterId string, chapterContainer []byte) error {
|
||||
container := models.MangaChapterContainer{
|
||||
Provider: provider,
|
||||
MediaID: mediaId,
|
||||
ChapterID: chapterId,
|
||||
Data: chapterContainer,
|
||||
}
|
||||
|
||||
mangaChapterContainerCache.Set(formatMangaChapterContainerCacheKey(provider, mediaId, chapterId), &container)
|
||||
|
||||
return db.gormdb.Save(&container).Error
|
||||
}
|
||||
|
||||
func (db *Database) DeleteMangaChapterContainer(provider string, mediaId int, chapterId string) error {
|
||||
err := db.gormdb.Where("provider = ? AND media_id = ? AND chapter_id = ?", provider, mediaId, chapterId).Delete(&models.MangaChapterContainer{}).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mangaChapterContainerCache.Delete(formatMangaChapterContainerCacheKey(provider, mediaId, chapterId))
|
||||
return nil
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
182
seanime-2.9.10/internal/database/db/media_filler.go
Normal file
182
seanime-2.9.10/internal/database/db/media_filler.go
Normal file
@@ -0,0 +1,182 @@
|
||||
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
|
||||
}
|
||||
24
seanime-2.9.10/internal/database/db/nakama.go
Normal file
24
seanime-2.9.10/internal/database/db/nakama.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"seanime/internal/database/models"
|
||||
)
|
||||
|
||||
func (db *Database) UpsertNakamaSettings(nakamaSettings *models.NakamaSettings) (*models.NakamaSettings, error) {
|
||||
|
||||
// Get current settings
|
||||
currentSettings, err := db.GetSettings()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Update the settings
|
||||
*(currentSettings.Nakama) = *nakamaSettings
|
||||
|
||||
_, err = db.UpsertSettings(currentSettings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nakamaSettings, nil
|
||||
}
|
||||
52
seanime-2.9.10/internal/database/db/onlinestream.go
Normal file
52
seanime-2.9.10/internal/database/db/onlinestream.go
Normal file
@@ -0,0 +1,52 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"seanime/internal/database/models"
|
||||
"seanime/internal/util/result"
|
||||
)
|
||||
|
||||
var onlinestreamMappingCache = result.NewResultMap[string, *models.OnlinestreamMapping]()
|
||||
|
||||
func formatOnlinestreamMappingCacheKey(provider string, mediaId int) string {
|
||||
return fmt.Sprintf("%s$%d", provider, mediaId)
|
||||
}
|
||||
|
||||
func (db *Database) GetOnlinestreamMapping(provider string, mediaId int) (*models.OnlinestreamMapping, bool) {
|
||||
|
||||
if res, ok := onlinestreamMappingCache.Get(formatOnlinestreamMappingCacheKey(provider, mediaId)); ok {
|
||||
return res, true
|
||||
}
|
||||
|
||||
var res models.OnlinestreamMapping
|
||||
err := db.gormdb.Where("provider = ? AND media_id = ?", provider, mediaId).First(&res).Error
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
onlinestreamMappingCache.Set(formatOnlinestreamMappingCacheKey(provider, mediaId), &res)
|
||||
|
||||
return &res, true
|
||||
}
|
||||
|
||||
func (db *Database) InsertOnlinestreamMapping(provider string, mediaId int, animeId string) error {
|
||||
mapping := models.OnlinestreamMapping{
|
||||
Provider: provider,
|
||||
MediaID: mediaId,
|
||||
AnimeID: animeId,
|
||||
}
|
||||
|
||||
onlinestreamMappingCache.Set(formatOnlinestreamMappingCacheKey(provider, mediaId), &mapping)
|
||||
|
||||
return db.gormdb.Save(&mapping).Error
|
||||
}
|
||||
|
||||
func (db *Database) DeleteOnlinestreamMapping(provider string, mediaId int) error {
|
||||
err := db.gormdb.Where("provider = ? AND media_id = ?", provider, mediaId).Delete(&models.OnlinestreamMapping{}).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
onlinestreamMappingCache.Delete(formatOnlinestreamMappingCacheKey(provider, mediaId))
|
||||
return nil
|
||||
}
|
||||
24
seanime-2.9.10/internal/database/db/scan_summary.go
Normal file
24
seanime-2.9.10/internal/database/db/scan_summary.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"seanime/internal/database/models"
|
||||
)
|
||||
|
||||
func (db *Database) TrimScanSummaryEntries() {
|
||||
go func() {
|
||||
var count int64
|
||||
err := db.gormdb.Model(&models.ScanSummary{}).Count(&count).Error
|
||||
if err != nil {
|
||||
db.Logger.Error().Err(err).Msg("Failed to count scan summary entries")
|
||||
return
|
||||
}
|
||||
if count > 10 {
|
||||
// Leave 5 entries
|
||||
err = db.gormdb.Delete(&models.ScanSummary{}, "id IN (SELECT id FROM scan_summaries ORDER BY id ASC LIMIT ?)", count-5).Error
|
||||
if err != nil {
|
||||
db.Logger.Error().Err(err).Msg("Failed to delete old scan summary entries")
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
200
seanime-2.9.10/internal/database/db/settings.go
Normal file
200
seanime-2.9.10/internal/database/db/settings.go
Normal file
@@ -0,0 +1,200 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"seanime/internal/database/models"
|
||||
|
||||
"gorm.io/gorm/clause"
|
||||
)
|
||||
|
||||
var CurrSettings *models.Settings
|
||||
|
||||
func (db *Database) UpsertSettings(settings *models.Settings) (*models.Settings, error) {
|
||||
|
||||
err := db.gormdb.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "id"}},
|
||||
UpdateAll: true,
|
||||
}).Create(settings).Error
|
||||
|
||||
if err != nil {
|
||||
db.Logger.Error().Err(err).Msg("db: Failed to save settings in the database")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
CurrSettings = settings
|
||||
|
||||
db.Logger.Debug().Msg("db: Settings saved")
|
||||
return settings, nil
|
||||
|
||||
}
|
||||
|
||||
func (db *Database) GetSettings() (*models.Settings, error) {
|
||||
|
||||
if CurrSettings != nil {
|
||||
return CurrSettings, nil
|
||||
}
|
||||
|
||||
var settings models.Settings
|
||||
err := db.gormdb.Where("id = ?", 1).Find(&settings).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &settings, nil
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
func (db *Database) GetLibraryPathFromSettings() (string, error) {
|
||||
settings, err := db.GetSettings()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return settings.Library.LibraryPath, nil
|
||||
}
|
||||
|
||||
func (db *Database) GetAdditionalLibraryPathsFromSettings() ([]string, error) {
|
||||
settings, err := db.GetSettings()
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
return settings.Library.LibraryPaths, nil
|
||||
}
|
||||
|
||||
func (db *Database) GetAllLibraryPathsFromSettings() ([]string, error) {
|
||||
settings, err := db.GetSettings()
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
if settings.Library == nil {
|
||||
return []string{}, nil
|
||||
}
|
||||
return append([]string{settings.Library.LibraryPath}, settings.Library.LibraryPaths...), nil
|
||||
}
|
||||
|
||||
func (db *Database) AllLibraryPathsFromSettings(settings *models.Settings) *[]string {
|
||||
if settings.Library == nil {
|
||||
return &[]string{}
|
||||
}
|
||||
r := append([]string{settings.Library.LibraryPath}, settings.Library.LibraryPaths...)
|
||||
return &r
|
||||
}
|
||||
|
||||
func (db *Database) AutoUpdateProgressIsEnabled() (bool, error) {
|
||||
settings, err := db.GetSettings()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return settings.Library.AutoUpdateProgress, nil
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var CurrMediastreamSettings *models.MediastreamSettings
|
||||
|
||||
func (db *Database) UpsertMediastreamSettings(settings *models.MediastreamSettings) (*models.MediastreamSettings, error) {
|
||||
|
||||
err := db.gormdb.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "id"}},
|
||||
UpdateAll: true,
|
||||
}).Create(settings).Error
|
||||
|
||||
if err != nil {
|
||||
db.Logger.Error().Err(err).Msg("db: Failed to save media streaming settings in the database")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
CurrMediastreamSettings = settings
|
||||
|
||||
db.Logger.Debug().Msg("db: Media streaming settings saved")
|
||||
return settings, nil
|
||||
|
||||
}
|
||||
|
||||
func (db *Database) GetMediastreamSettings() (*models.MediastreamSettings, bool) {
|
||||
|
||||
if CurrMediastreamSettings != nil {
|
||||
return CurrMediastreamSettings, true
|
||||
}
|
||||
|
||||
var settings models.MediastreamSettings
|
||||
err := db.gormdb.Where("id = ?", 1).First(&settings).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
return &settings, true
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var CurrTorrentstreamSettings *models.TorrentstreamSettings
|
||||
|
||||
func (db *Database) UpsertTorrentstreamSettings(settings *models.TorrentstreamSettings) (*models.TorrentstreamSettings, error) {
|
||||
|
||||
err := db.gormdb.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "id"}},
|
||||
UpdateAll: true,
|
||||
}).Create(settings).Error
|
||||
|
||||
if err != nil {
|
||||
db.Logger.Error().Err(err).Msg("db: Failed to save torrent streaming settings in the database")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
CurrTorrentstreamSettings = settings
|
||||
|
||||
db.Logger.Debug().Msg("db: Torrent streaming settings saved")
|
||||
return settings, nil
|
||||
}
|
||||
|
||||
func (db *Database) GetTorrentstreamSettings() (*models.TorrentstreamSettings, bool) {
|
||||
|
||||
if CurrTorrentstreamSettings != nil {
|
||||
return CurrTorrentstreamSettings, true
|
||||
}
|
||||
|
||||
var settings models.TorrentstreamSettings
|
||||
err := db.gormdb.Where("id = ?", 1).First(&settings).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
return &settings, true
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var CurrentDebridSettings *models.DebridSettings
|
||||
|
||||
func (db *Database) UpsertDebridSettings(settings *models.DebridSettings) (*models.DebridSettings, error) {
|
||||
err := db.gormdb.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "id"}},
|
||||
UpdateAll: true,
|
||||
}).Create(settings).Error
|
||||
|
||||
if err != nil {
|
||||
db.Logger.Error().Err(err).Msg("db: Failed to save debrid settings in the database")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
CurrentDebridSettings = settings
|
||||
|
||||
db.Logger.Debug().Msg("db: Debrid settings saved")
|
||||
return settings, nil
|
||||
}
|
||||
|
||||
func (db *Database) GetDebridSettings() (*models.DebridSettings, bool) {
|
||||
|
||||
if CurrentDebridSettings != nil {
|
||||
return CurrentDebridSettings, true
|
||||
}
|
||||
|
||||
var settings models.DebridSettings
|
||||
err := db.gormdb.Where("id = ?", 1).First(&settings).Error
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
return &settings, true
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
70
seanime-2.9.10/internal/database/db/silenced_media_entry.go
Normal file
70
seanime-2.9.10/internal/database/db/silenced_media_entry.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"gorm.io/gorm/clause"
|
||||
"seanime/internal/database/models"
|
||||
)
|
||||
|
||||
func (db *Database) GetSilencedMediaEntries() ([]*models.SilencedMediaEntry, error) {
|
||||
var res []*models.SilencedMediaEntry
|
||||
err := db.gormdb.Find(&res).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// GetSilencedMediaEntryIds returns the ids of all silenced media entries.
|
||||
// It returns an empty slice if there is an error.
|
||||
func (db *Database) GetSilencedMediaEntryIds() ([]int, error) {
|
||||
var res []*models.SilencedMediaEntry
|
||||
err := db.gormdb.Find(&res).Error
|
||||
if err != nil {
|
||||
return make([]int, 0), err
|
||||
}
|
||||
|
||||
if len(res) == 0 {
|
||||
return make([]int, 0), nil
|
||||
}
|
||||
|
||||
mIds := make([]int, len(res))
|
||||
for i, v := range res {
|
||||
mIds[i] = int(v.ID)
|
||||
}
|
||||
|
||||
return mIds, nil
|
||||
}
|
||||
|
||||
func (db *Database) GetSilencedMediaEntry(mId uint) (*models.SilencedMediaEntry, error) {
|
||||
var res models.SilencedMediaEntry
|
||||
err := db.gormdb.First(&res, mId).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func (db *Database) InsertSilencedMediaEntry(mId uint) error {
|
||||
err := db.gormdb.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "id"}},
|
||||
UpdateAll: true,
|
||||
}).Create(&models.SilencedMediaEntry{
|
||||
BaseModel: models.BaseModel{
|
||||
ID: mId,
|
||||
},
|
||||
}).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) DeleteSilencedMediaEntry(id uint) error {
|
||||
err := db.gormdb.Delete(&models.SilencedMediaEntry{}, id).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
47
seanime-2.9.10/internal/database/db/theme.go
Normal file
47
seanime-2.9.10/internal/database/db/theme.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"gorm.io/gorm/clause"
|
||||
"seanime/internal/database/models"
|
||||
)
|
||||
|
||||
var themeCache *models.Theme
|
||||
|
||||
func (db *Database) GetTheme() (*models.Theme, error) {
|
||||
|
||||
if themeCache != nil {
|
||||
return themeCache, nil
|
||||
}
|
||||
|
||||
var theme models.Theme
|
||||
err := db.gormdb.Where("id = ?", 1).Find(&theme).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
themeCache = &theme
|
||||
|
||||
return &theme, nil
|
||||
}
|
||||
|
||||
// UpsertTheme updates the theme settings.
|
||||
func (db *Database) UpsertTheme(settings *models.Theme) (*models.Theme, error) {
|
||||
|
||||
err := db.gormdb.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "id"}},
|
||||
UpdateAll: true,
|
||||
}).Create(settings).Error
|
||||
|
||||
if err != nil {
|
||||
db.Logger.Error().Err(err).Msg("db: Failed to save theme in the database")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
db.Logger.Debug().Msg("db: Theme saved")
|
||||
|
||||
themeCache = settings
|
||||
|
||||
return settings, nil
|
||||
|
||||
}
|
||||
21
seanime-2.9.10/internal/database/db/token.go
Normal file
21
seanime-2.9.10/internal/database/db/token.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"gorm.io/gorm/clause"
|
||||
"seanime/internal/database/models"
|
||||
)
|
||||
|
||||
func (db *Database) UpsertToken(token *models.Token) (*models.Token, error) {
|
||||
|
||||
err := db.gormdb.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "id"}},
|
||||
DoUpdates: clause.AssignmentColumns([]string{"value", "updated_at"}),
|
||||
}).Create(token).Error
|
||||
|
||||
if err != nil {
|
||||
db.Logger.Error().Err(err).Msg("Failed to save token in the database")
|
||||
return nil, err
|
||||
}
|
||||
return token, nil
|
||||
|
||||
}
|
||||
24
seanime-2.9.10/internal/database/db/torrentstream_history.go
Normal file
24
seanime-2.9.10/internal/database/db/torrentstream_history.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"seanime/internal/database/models"
|
||||
)
|
||||
|
||||
func (db *Database) TrimTorrentstreamHistory() {
|
||||
go func() {
|
||||
var count int64
|
||||
err := db.gormdb.Model(&models.TorrentstreamHistory{}).Count(&count).Error
|
||||
if err != nil {
|
||||
db.Logger.Error().Err(err).Msg("database: Failed to count torrent stream history entries")
|
||||
return
|
||||
}
|
||||
if count > 50 {
|
||||
// Leave 40 entries
|
||||
err = db.gormdb.Delete(&models.TorrentstreamHistory{}, "id IN (SELECT id FROM torrentstream_histories ORDER BY updated_at ASC LIMIT ?)", 10).Error
|
||||
if err != nil {
|
||||
db.Logger.Error().Err(err).Msg("database: Failed to delete old torrent stream history entries")
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
2
seanime-2.9.10/internal/database/db_bridge/README.md
Normal file
2
seanime-2.9.10/internal/database/db_bridge/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
The database may store some structs defined outside as `[]byte` inside `models`.
|
||||
To avoid circular dependencies, we define methods that directly convert `[]byte` to the corresponding struct using the database to store/retrieve them.
|
||||
@@ -0,0 +1,109 @@
|
||||
package db_bridge
|
||||
|
||||
import (
|
||||
"github.com/goccy/go-json"
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/database/models"
|
||||
"seanime/internal/library/anime"
|
||||
)
|
||||
|
||||
var CurrAutoDownloaderRules []*anime.AutoDownloaderRule
|
||||
|
||||
func GetAutoDownloaderRules(db *db.Database) ([]*anime.AutoDownloaderRule, error) {
|
||||
|
||||
//if CurrAutoDownloaderRules != nil {
|
||||
// return CurrAutoDownloaderRules, nil
|
||||
//}
|
||||
|
||||
var res []*models.AutoDownloaderRule
|
||||
err := db.Gorm().Find(&res).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Unmarshal the data
|
||||
var rules []*anime.AutoDownloaderRule
|
||||
for _, r := range res {
|
||||
smBytes := r.Value
|
||||
var sm anime.AutoDownloaderRule
|
||||
if err := json.Unmarshal(smBytes, &sm); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sm.DbID = r.ID
|
||||
rules = append(rules, &sm)
|
||||
}
|
||||
|
||||
//CurrAutoDownloaderRules = rules
|
||||
|
||||
return rules, nil
|
||||
}
|
||||
|
||||
func GetAutoDownloaderRule(db *db.Database, id uint) (*anime.AutoDownloaderRule, error) {
|
||||
var res models.AutoDownloaderRule
|
||||
err := db.Gorm().First(&res, id).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Unmarshal the data
|
||||
smBytes := res.Value
|
||||
var sm anime.AutoDownloaderRule
|
||||
if err := json.Unmarshal(smBytes, &sm); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sm.DbID = res.ID
|
||||
|
||||
return &sm, nil
|
||||
}
|
||||
|
||||
func GetAutoDownloaderRulesByMediaId(db *db.Database, mediaId int) (ret []*anime.AutoDownloaderRule) {
|
||||
rules, err := GetAutoDownloaderRules(db)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, rule := range rules {
|
||||
if rule.MediaId == mediaId {
|
||||
ret = append(ret, rule)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func InsertAutoDownloaderRule(db *db.Database, sm *anime.AutoDownloaderRule) error {
|
||||
|
||||
CurrAutoDownloaderRules = nil
|
||||
|
||||
// Marshal the data
|
||||
bytes, err := json.Marshal(sm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Save the data
|
||||
return db.Gorm().Create(&models.AutoDownloaderRule{
|
||||
Value: bytes,
|
||||
}).Error
|
||||
}
|
||||
|
||||
func DeleteAutoDownloaderRule(db *db.Database, id uint) error {
|
||||
|
||||
CurrAutoDownloaderRules = nil
|
||||
|
||||
return db.Gorm().Delete(&models.AutoDownloaderRule{}, id).Error
|
||||
}
|
||||
|
||||
func UpdateAutoDownloaderRule(db *db.Database, id uint, sm *anime.AutoDownloaderRule) error {
|
||||
|
||||
CurrAutoDownloaderRules = nil
|
||||
|
||||
// Marshal the data
|
||||
bytes, err := json.Marshal(sm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Save the data
|
||||
return db.Gorm().Model(&models.AutoDownloaderRule{}).Where("id = ?", id).Update("value", bytes).Error
|
||||
}
|
||||
97
seanime-2.9.10/internal/database/db_bridge/localfiles.go
Normal file
97
seanime-2.9.10/internal/database/db_bridge/localfiles.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package db_bridge
|
||||
|
||||
import (
|
||||
"github.com/goccy/go-json"
|
||||
"github.com/samber/mo"
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/database/models"
|
||||
"seanime/internal/library/anime"
|
||||
)
|
||||
|
||||
var CurrLocalFilesDbId uint
|
||||
var CurrLocalFiles mo.Option[[]*anime.LocalFile]
|
||||
|
||||
// GetLocalFiles will return the latest local files and the id of the entry.
|
||||
func GetLocalFiles(db *db.Database) ([]*anime.LocalFile, uint, error) {
|
||||
|
||||
if CurrLocalFiles.IsPresent() {
|
||||
return CurrLocalFiles.MustGet(), CurrLocalFilesDbId, nil
|
||||
}
|
||||
|
||||
// Get the latest entry
|
||||
var res models.LocalFiles
|
||||
err := db.Gorm().Last(&res).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// Unmarshal the local files
|
||||
lfsBytes := res.Value
|
||||
var lfs []*anime.LocalFile
|
||||
if err := json.Unmarshal(lfsBytes, &lfs); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
db.Logger.Debug().Msg("db: Local files retrieved")
|
||||
|
||||
CurrLocalFiles = mo.Some(lfs)
|
||||
CurrLocalFilesDbId = res.ID
|
||||
|
||||
return lfs, res.ID, nil
|
||||
}
|
||||
|
||||
// SaveLocalFiles will save the local files in the database at the given id.
|
||||
func SaveLocalFiles(db *db.Database, lfsId uint, lfs []*anime.LocalFile) ([]*anime.LocalFile, error) {
|
||||
// Marshal the local files
|
||||
marshaledLfs, err := json.Marshal(lfs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Save the local files
|
||||
ret, err := db.UpsertLocalFiles(&models.LocalFiles{
|
||||
BaseModel: models.BaseModel{
|
||||
ID: lfsId,
|
||||
},
|
||||
Value: marshaledLfs,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Unmarshal the saved local files
|
||||
var retLfs []*anime.LocalFile
|
||||
if err := json.Unmarshal(ret.Value, &retLfs); err != nil {
|
||||
return lfs, nil
|
||||
}
|
||||
|
||||
CurrLocalFiles = mo.Some(retLfs)
|
||||
CurrLocalFilesDbId = ret.ID
|
||||
|
||||
return retLfs, nil
|
||||
}
|
||||
|
||||
// InsertLocalFiles will insert the local files in the database at a new entry.
|
||||
func InsertLocalFiles(db *db.Database, lfs []*anime.LocalFile) ([]*anime.LocalFile, error) {
|
||||
|
||||
// Marshal the local files
|
||||
bytes, err := json.Marshal(lfs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Save the local files to the database
|
||||
ret, err := db.InsertLocalFiles(&models.LocalFiles{
|
||||
Value: bytes,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
CurrLocalFiles = mo.Some(lfs)
|
||||
CurrLocalFilesDbId = ret.ID
|
||||
|
||||
return lfs, nil
|
||||
|
||||
}
|
||||
82
seanime-2.9.10/internal/database/db_bridge/playlist.go
Normal file
82
seanime-2.9.10/internal/database/db_bridge/playlist.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package db_bridge
|
||||
|
||||
import (
|
||||
"github.com/goccy/go-json"
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/database/models"
|
||||
"seanime/internal/library/anime"
|
||||
)
|
||||
|
||||
func GetPlaylists(db *db.Database) ([]*anime.Playlist, error) {
|
||||
var res []*models.PlaylistEntry
|
||||
err := db.Gorm().Find(&res).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
playlists := make([]*anime.Playlist, 0)
|
||||
for _, p := range res {
|
||||
var localFiles []*anime.LocalFile
|
||||
if err := json.Unmarshal(p.Value, &localFiles); err == nil {
|
||||
playlist := anime.NewPlaylist(p.Name)
|
||||
playlist.SetLocalFiles(localFiles)
|
||||
playlist.DbId = p.ID
|
||||
playlists = append(playlists, playlist)
|
||||
}
|
||||
}
|
||||
return playlists, nil
|
||||
}
|
||||
|
||||
func SavePlaylist(db *db.Database, playlist *anime.Playlist) error {
|
||||
data, err := json.Marshal(playlist.LocalFiles)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
playlistEntry := &models.PlaylistEntry{
|
||||
Name: playlist.Name,
|
||||
Value: data,
|
||||
}
|
||||
|
||||
return db.Gorm().Save(playlistEntry).Error
|
||||
}
|
||||
|
||||
func DeletePlaylist(db *db.Database, id uint) error {
|
||||
return db.Gorm().Where("id = ?", id).Delete(&models.PlaylistEntry{}).Error
|
||||
}
|
||||
|
||||
func UpdatePlaylist(db *db.Database, playlist *anime.Playlist) error {
|
||||
data, err := json.Marshal(playlist.LocalFiles)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get the playlist entry
|
||||
playlistEntry := &models.PlaylistEntry{}
|
||||
if err := db.Gorm().Where("id = ?", playlist.DbId).First(playlistEntry).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Update the playlist entry
|
||||
playlistEntry.Name = playlist.Name
|
||||
playlistEntry.Value = data
|
||||
|
||||
return db.Gorm().Save(playlistEntry).Error
|
||||
}
|
||||
|
||||
func GetPlaylist(db *db.Database, id uint) (*anime.Playlist, error) {
|
||||
playlistEntry := &models.PlaylistEntry{}
|
||||
if err := db.Gorm().Where("id = ?", id).First(playlistEntry).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var localFiles []*anime.LocalFile
|
||||
if err := json.Unmarshal(playlistEntry.Value, &localFiles); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
playlist := anime.NewPlaylist(playlistEntry.Name)
|
||||
playlist.SetLocalFiles(localFiles)
|
||||
playlist.DbId = playlistEntry.ID
|
||||
|
||||
return playlist, nil
|
||||
}
|
||||
50
seanime-2.9.10/internal/database/db_bridge/scan_summary.go
Normal file
50
seanime-2.9.10/internal/database/db_bridge/scan_summary.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package db_bridge
|
||||
|
||||
import (
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/database/models"
|
||||
"seanime/internal/library/summary"
|
||||
|
||||
"github.com/goccy/go-json"
|
||||
)
|
||||
|
||||
func GetScanSummaries(database *db.Database) ([]*summary.ScanSummaryItem, error) {
|
||||
var res []*models.ScanSummary
|
||||
err := database.Gorm().Find(&res).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Unmarshal the data
|
||||
var items []*summary.ScanSummaryItem
|
||||
for _, r := range res {
|
||||
smBytes := r.Value
|
||||
var sm summary.ScanSummary
|
||||
if err := json.Unmarshal(smBytes, &sm); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, &summary.ScanSummaryItem{
|
||||
CreatedAt: r.CreatedAt,
|
||||
ScanSummary: &sm,
|
||||
})
|
||||
}
|
||||
|
||||
return items, nil
|
||||
}
|
||||
|
||||
func InsertScanSummary(db *db.Database, sm *summary.ScanSummary) error {
|
||||
if sm == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Marshal the data
|
||||
bytes, err := json.Marshal(sm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Save the data
|
||||
return db.Gorm().Create(&models.ScanSummary{
|
||||
Value: bytes,
|
||||
}).Error
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package db_bridge
|
||||
|
||||
import (
|
||||
"github.com/goccy/go-json"
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/database/models"
|
||||
hibiketorrent "seanime/internal/extension/hibike/torrent"
|
||||
)
|
||||
|
||||
func GetTorrentstreamHistory(db *db.Database, mId int) (*hibiketorrent.AnimeTorrent, error) {
|
||||
var history models.TorrentstreamHistory
|
||||
if err := db.Gorm().Where("media_id = ?", mId).First(&history).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var torrent hibiketorrent.AnimeTorrent
|
||||
if err := json.Unmarshal(history.Torrent, &torrent); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &torrent, nil
|
||||
}
|
||||
|
||||
func InsertTorrentstreamHistory(db *db.Database, mId int, torrent *hibiketorrent.AnimeTorrent) error {
|
||||
if torrent == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Marshal the data
|
||||
bytes, err := json.Marshal(torrent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get current history
|
||||
var history models.TorrentstreamHistory
|
||||
if err := db.Gorm().Where("media_id = ?", mId).First(&history).Error; err == nil {
|
||||
// Update the history
|
||||
history.Torrent = bytes
|
||||
return db.Gorm().Save(&history).Error
|
||||
}
|
||||
|
||||
return db.Gorm().Create(&models.TorrentstreamHistory{
|
||||
MediaId: mId,
|
||||
Torrent: bytes,
|
||||
}).Error
|
||||
}
|
||||
511
seanime-2.9.10/internal/database/models/models.go
Normal file
511
seanime-2.9.10/internal/database/models/models.go
Normal file
@@ -0,0 +1,511 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type BaseModel struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
type Token struct {
|
||||
BaseModel
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type Account struct {
|
||||
BaseModel
|
||||
Username string `gorm:"column:username" json:"username"`
|
||||
Token string `gorm:"column:token" json:"token"`
|
||||
Viewer []byte `gorm:"column:viewer" json:"viewer"`
|
||||
}
|
||||
|
||||
// +---------------------+
|
||||
// | LocalFiles |
|
||||
// +---------------------+
|
||||
|
||||
type LocalFiles struct {
|
||||
BaseModel
|
||||
Value []byte `gorm:"column:value" json:"value"`
|
||||
}
|
||||
|
||||
// +---------------------+
|
||||
// | Settings |
|
||||
// +---------------------+
|
||||
|
||||
type Settings struct {
|
||||
BaseModel
|
||||
Library *LibrarySettings `gorm:"embedded" json:"library"`
|
||||
MediaPlayer *MediaPlayerSettings `gorm:"embedded" json:"mediaPlayer"`
|
||||
Torrent *TorrentSettings `gorm:"embedded" json:"torrent"`
|
||||
Manga *MangaSettings `gorm:"embedded" json:"manga"`
|
||||
Anilist *AnilistSettings `gorm:"embedded" json:"anilist"`
|
||||
ListSync *ListSyncSettings `gorm:"embedded" json:"listSync"`
|
||||
AutoDownloader *AutoDownloaderSettings `gorm:"embedded" json:"autoDownloader"`
|
||||
Discord *DiscordSettings `gorm:"embedded" json:"discord"`
|
||||
Notifications *NotificationSettings `gorm:"embedded" json:"notifications"`
|
||||
Nakama *NakamaSettings `gorm:"embedded;embeddedPrefix:nakama_" json:"nakama"`
|
||||
}
|
||||
|
||||
type AnilistSettings struct {
|
||||
//AnilistClientId string `gorm:"column:anilist_client_id" json:"anilistClientId"`
|
||||
HideAudienceScore bool `gorm:"column:hide_audience_score" json:"hideAudienceScore"`
|
||||
EnableAdultContent bool `gorm:"column:enable_adult_content" json:"enableAdultContent"`
|
||||
BlurAdultContent bool `gorm:"column:blur_adult_content" json:"blurAdultContent"`
|
||||
}
|
||||
|
||||
type LibrarySettings struct {
|
||||
LibraryPath string `gorm:"column:library_path" json:"libraryPath"`
|
||||
AutoUpdateProgress bool `gorm:"column:auto_update_progress" json:"autoUpdateProgress"`
|
||||
DisableUpdateCheck bool `gorm:"column:disable_update_check" json:"disableUpdateCheck"`
|
||||
TorrentProvider string `gorm:"column:torrent_provider" json:"torrentProvider"`
|
||||
AutoScan bool `gorm:"column:auto_scan" json:"autoScan"`
|
||||
EnableOnlinestream bool `gorm:"column:enable_onlinestream" json:"enableOnlinestream"`
|
||||
IncludeOnlineStreamingInLibrary bool `gorm:"column:include_online_streaming_in_library" json:"includeOnlineStreamingInLibrary"`
|
||||
DisableAnimeCardTrailers bool `gorm:"column:disable_anime_card_trailers" json:"disableAnimeCardTrailers"`
|
||||
EnableManga bool `gorm:"column:enable_manga" json:"enableManga"`
|
||||
DOHProvider string `gorm:"column:doh_provider" json:"dohProvider"`
|
||||
OpenTorrentClientOnStart bool `gorm:"column:open_torrent_client_on_start" json:"openTorrentClientOnStart"`
|
||||
OpenWebURLOnStart bool `gorm:"column:open_web_url_on_start" json:"openWebURLOnStart"`
|
||||
RefreshLibraryOnStart bool `gorm:"column:refresh_library_on_start" json:"refreshLibraryOnStart"`
|
||||
// v2.1+
|
||||
AutoPlayNextEpisode bool `gorm:"column:auto_play_next_episode" json:"autoPlayNextEpisode"`
|
||||
// v2.2+
|
||||
EnableWatchContinuity bool `gorm:"column:enable_watch_continuity" json:"enableWatchContinuity"`
|
||||
LibraryPaths LibraryPaths `gorm:"column:library_paths;type:text" json:"libraryPaths"`
|
||||
AutoSyncOfflineLocalData bool `gorm:"column:auto_sync_offline_local_data" json:"autoSyncOfflineLocalData"`
|
||||
// v2.6+
|
||||
ScannerMatchingThreshold float64 `gorm:"column:scanner_matching_threshold" json:"scannerMatchingThreshold"`
|
||||
ScannerMatchingAlgorithm string `gorm:"column:scanner_matching_algorithm" json:"scannerMatchingAlgorithm"`
|
||||
// v2.9+
|
||||
AutoSyncToLocalAccount bool `gorm:"column:auto_sync_to_local_account" json:"autoSyncToLocalAccount"`
|
||||
AutoSaveCurrentMediaOffline bool `gorm:"column:auto_save_current_media_offline" json:"autoSaveCurrentMediaOffline"`
|
||||
}
|
||||
|
||||
func (o *LibrarySettings) GetLibraryPaths() (ret []string) {
|
||||
ret = make([]string, len(o.LibraryPaths)+1)
|
||||
ret[0] = o.LibraryPath
|
||||
if len(o.LibraryPaths) > 0 {
|
||||
copy(ret[1:], o.LibraryPaths)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type LibraryPaths []string
|
||||
|
||||
func (o *LibraryPaths) Scan(src interface{}) error {
|
||||
str, ok := src.(string)
|
||||
if !ok {
|
||||
return errors.New("src value cannot cast to string")
|
||||
}
|
||||
*o = strings.Split(str, ",")
|
||||
return nil
|
||||
}
|
||||
func (o LibraryPaths) Value() (driver.Value, error) {
|
||||
if len(o) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return strings.Join(o, ","), nil
|
||||
}
|
||||
|
||||
type NakamaSettings struct {
|
||||
Enabled bool `gorm:"column:enabled" json:"enabled"`
|
||||
// Username is the name used to identify a peer or host.
|
||||
Username string `gorm:"column:username" json:"username"`
|
||||
// IsHost allows the server to act as a host for other clients. This requires a password to be set.
|
||||
IsHost bool `gorm:"column:is_host" json:"isHost"`
|
||||
HostPassword string `gorm:"column:host_password" json:"hostPassword"`
|
||||
RemoteServerURL string `gorm:"column:remote_server_url" json:"remoteServerURL"`
|
||||
RemoteServerPassword string `gorm:"column:remote_server_password" json:"remoteServerPassword"`
|
||||
// IncludeNakamaAnimeLibrary adds the local anime library of the host to the connected clients.
|
||||
IncludeNakamaAnimeLibrary bool `gorm:"column:include_nakama_anime_library" json:"includeNakamaAnimeLibrary"`
|
||||
// HostShareLocalAnimeLibrary shares the local anime library to connected clients
|
||||
HostShareLocalAnimeLibrary bool `gorm:"column:host_share_local_anime_library" json:"hostShareLocalAnimeLibrary"`
|
||||
// HostUnsharedAnimeIds is a list of anime IDs that should not be shared with connected clients.
|
||||
HostUnsharedAnimeIds IntSlice `gorm:"column:host_unshared_anime_ids;type:text" json:"hostUnsharedAnimeIds"`
|
||||
// HostEnablePortForwarding enables port forwarding.
|
||||
HostEnablePortForwarding bool `gorm:"column:host_enable_port_forwarding" json:"hostEnablePortForwarding"`
|
||||
}
|
||||
|
||||
type IntSlice []int
|
||||
|
||||
func (o *IntSlice) Scan(src interface{}) error {
|
||||
str, ok := src.(string)
|
||||
if !ok {
|
||||
return errors.New("src value cannot cast to string")
|
||||
}
|
||||
ids := strings.Split(str, ",")
|
||||
*o = make(IntSlice, len(ids))
|
||||
for i, id := range ids {
|
||||
(*o)[i], _ = strconv.Atoi(id)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (o IntSlice) Value() (driver.Value, error) {
|
||||
if len(o) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
strs := make([]string, len(o))
|
||||
for i, id := range o {
|
||||
strs[i] = strconv.Itoa(id)
|
||||
}
|
||||
return strings.Join(strs, ","), nil
|
||||
}
|
||||
|
||||
type MangaSettings struct {
|
||||
DefaultProvider string `gorm:"column:default_manga_provider" json:"defaultMangaProvider"`
|
||||
AutoUpdateProgress bool `gorm:"column:manga_auto_update_progress" json:"mangaAutoUpdateProgress"`
|
||||
LocalSourceDirectory string `gorm:"column:manga_local_source_directory" json:"mangaLocalSourceDirectory"`
|
||||
}
|
||||
|
||||
type MediaPlayerSettings struct {
|
||||
Default string `gorm:"column:default_player" json:"defaultPlayer"` // "vlc" or "mpc-hc"
|
||||
Host string `gorm:"column:player_host" json:"host"`
|
||||
VlcUsername string `gorm:"column:vlc_username" json:"vlcUsername"`
|
||||
VlcPassword string `gorm:"column:vlc_password" json:"vlcPassword"`
|
||||
VlcPort int `gorm:"column:vlc_port" json:"vlcPort"`
|
||||
VlcPath string `gorm:"column:vlc_path" json:"vlcPath"`
|
||||
MpcPort int `gorm:"column:mpc_port" json:"mpcPort"`
|
||||
MpcPath string `gorm:"column:mpc_path" json:"mpcPath"`
|
||||
MpvSocket string `gorm:"column:mpv_socket" json:"mpvSocket"`
|
||||
MpvPath string `gorm:"column:mpv_path" json:"mpvPath"`
|
||||
MpvArgs string `gorm:"column:mpv_args" json:"mpvArgs"`
|
||||
IinaSocket string `gorm:"column:iina_socket" json:"iinaSocket"`
|
||||
IinaPath string `gorm:"column:iina_path" json:"iinaPath"`
|
||||
IinaArgs string `gorm:"column:iina_args" json:"iinaArgs"`
|
||||
}
|
||||
|
||||
type TorrentSettings struct {
|
||||
Default string `gorm:"column:default_torrent_client" json:"defaultTorrentClient"`
|
||||
QBittorrentPath string `gorm:"column:qbittorrent_path" json:"qbittorrentPath"`
|
||||
QBittorrentHost string `gorm:"column:qbittorrent_host" json:"qbittorrentHost"`
|
||||
QBittorrentPort int `gorm:"column:qbittorrent_port" json:"qbittorrentPort"`
|
||||
QBittorrentUsername string `gorm:"column:qbittorrent_username" json:"qbittorrentUsername"`
|
||||
QBittorrentPassword string `gorm:"column:qbittorrent_password" json:"qbittorrentPassword"`
|
||||
QBittorrentTags string `gorm:"column:qbittorrent_tags" json:"qbittorrentTags"`
|
||||
TransmissionPath string `gorm:"column:transmission_path" json:"transmissionPath"`
|
||||
TransmissionHost string `gorm:"column:transmission_host" json:"transmissionHost"`
|
||||
TransmissionPort int `gorm:"column:transmission_port" json:"transmissionPort"`
|
||||
TransmissionUsername string `gorm:"column:transmission_username" json:"transmissionUsername"`
|
||||
TransmissionPassword string `gorm:"column:transmission_password" json:"transmissionPassword"`
|
||||
// v2.1+
|
||||
ShowActiveTorrentCount bool `gorm:"column:show_active_torrent_count" json:"showActiveTorrentCount"`
|
||||
// v2.2+
|
||||
HideTorrentList bool `gorm:"column:hide_torrent_list" json:"hideTorrentList"`
|
||||
}
|
||||
|
||||
type ListSyncSettings struct {
|
||||
Automatic bool `gorm:"column:automatic_sync" json:"automatic"`
|
||||
Origin string `gorm:"column:sync_origin" json:"origin"`
|
||||
}
|
||||
|
||||
type DiscordSettings struct {
|
||||
EnableRichPresence bool `gorm:"column:enable_rich_presence" json:"enableRichPresence"`
|
||||
EnableAnimeRichPresence bool `gorm:"column:enable_anime_rich_presence" json:"enableAnimeRichPresence"`
|
||||
EnableMangaRichPresence bool `gorm:"column:enable_manga_rich_presence" json:"enableMangaRichPresence"`
|
||||
RichPresenceHideSeanimeRepositoryButton bool `gorm:"column:rich_presence_hide_seanime_repository_button" json:"richPresenceHideSeanimeRepositoryButton"`
|
||||
RichPresenceShowAniListMediaButton bool `gorm:"column:rich_presence_show_anilist_media_button" json:"richPresenceShowAniListMediaButton"`
|
||||
RichPresenceShowAniListProfileButton bool `gorm:"column:rich_presence_show_anilist_profile_button" json:"richPresenceShowAniListProfileButton"`
|
||||
RichPresenceUseMediaTitleStatus bool `gorm:"column:rich_presence_use_media_title_status;default:true" json:"richPresenceUseMediaTitleStatus"`
|
||||
}
|
||||
|
||||
type NotificationSettings struct {
|
||||
DisableNotifications bool `gorm:"column:disable_notifications" json:"disableNotifications"`
|
||||
DisableAutoDownloaderNotifications bool `gorm:"column:disable_auto_downloader_notifications" json:"disableAutoDownloaderNotifications"`
|
||||
DisableAutoScannerNotifications bool `gorm:"column:disable_auto_scanner_notifications" json:"disableAutoScannerNotifications"`
|
||||
}
|
||||
|
||||
// +---------------------+
|
||||
// | MAL |
|
||||
// +---------------------+
|
||||
|
||||
type Mal struct {
|
||||
BaseModel
|
||||
Username string `gorm:"column:username" json:"username"`
|
||||
AccessToken string `gorm:"column:access_token" json:"accessToken"`
|
||||
RefreshToken string `gorm:"column:refresh_token" json:"refreshToken"`
|
||||
TokenExpiresAt time.Time `gorm:"column:token_expires_at" json:"tokenExpiresAt"`
|
||||
}
|
||||
|
||||
// +---------------------+
|
||||
// | Scan Summary |
|
||||
// +---------------------+
|
||||
|
||||
type ScanSummary struct {
|
||||
BaseModel
|
||||
Value []byte `gorm:"column:value" json:"value"`
|
||||
}
|
||||
|
||||
// +---------------------+
|
||||
// | Auto downloader |
|
||||
// +---------------------+
|
||||
|
||||
type AutoDownloaderRule struct {
|
||||
BaseModel
|
||||
Value []byte `gorm:"column:value" json:"value"`
|
||||
}
|
||||
|
||||
type AutoDownloaderItem struct {
|
||||
BaseModel
|
||||
RuleID uint `gorm:"column:rule_id" json:"ruleId"`
|
||||
MediaID int `gorm:"column:media_id" json:"mediaId"`
|
||||
Episode int `gorm:"column:episode" json:"episode"`
|
||||
Link string `gorm:"column:link" json:"link"`
|
||||
Hash string `gorm:"column:hash" json:"hash"`
|
||||
Magnet string `gorm:"column:magnet" json:"magnet"`
|
||||
TorrentName string `gorm:"column:torrent_name" json:"torrentName"`
|
||||
Downloaded bool `gorm:"column:downloaded" json:"downloaded"`
|
||||
}
|
||||
|
||||
type AutoDownloaderSettings struct {
|
||||
Provider string `gorm:"column:auto_downloader_provider" json:"provider"`
|
||||
Interval int `gorm:"column:auto_downloader_interval" json:"interval"`
|
||||
Enabled bool `gorm:"column:auto_downloader_enabled" json:"enabled"`
|
||||
DownloadAutomatically bool `gorm:"column:auto_downloader_download_automatically" json:"downloadAutomatically"`
|
||||
EnableEnhancedQueries bool `gorm:"column:auto_downloader_enable_enhanced_queries" json:"enableEnhancedQueries"`
|
||||
EnableSeasonCheck bool `gorm:"column:auto_downloader_enable_season_check" json:"enableSeasonCheck"`
|
||||
UseDebrid bool `gorm:"column:auto_downloader_use_debrid" json:"useDebrid"`
|
||||
}
|
||||
|
||||
// +---------------------+
|
||||
// | Media Entry |
|
||||
// +---------------------+
|
||||
|
||||
type SilencedMediaEntry struct {
|
||||
BaseModel
|
||||
}
|
||||
|
||||
// +---------------------+
|
||||
// | Theme |
|
||||
// +---------------------+
|
||||
|
||||
type Theme struct {
|
||||
BaseModel
|
||||
// Main
|
||||
EnableColorSettings bool `gorm:"column:enable_color_settings" json:"enableColorSettings"`
|
||||
BackgroundColor string `gorm:"column:background_color" json:"backgroundColor"`
|
||||
AccentColor string `gorm:"column:accent_color" json:"accentColor"`
|
||||
SidebarBackgroundColor string `gorm:"column:sidebar_background_color" json:"sidebarBackgroundColor"` // DEPRECATED
|
||||
AnimeEntryScreenLayout string `gorm:"column:anime_entry_screen_layout" json:"animeEntryScreenLayout"` // DEPRECATED
|
||||
ExpandSidebarOnHover bool `gorm:"column:expand_sidebar_on_hover" json:"expandSidebarOnHover"`
|
||||
HideTopNavbar bool `gorm:"column:hide_top_navbar" json:"hideTopNavbar"`
|
||||
EnableMediaCardBlurredBackground bool `gorm:"column:enable_media_card_blurred_background" json:"enableMediaCardBlurredBackground"`
|
||||
// Note: These are named "libraryScreen" but are used on all pages
|
||||
LibraryScreenCustomBackgroundImage string `gorm:"column:library_screen_custom_background_image" json:"libraryScreenCustomBackgroundImage"`
|
||||
LibraryScreenCustomBackgroundOpacity int `gorm:"column:library_screen_custom_background_opacity" json:"libraryScreenCustomBackgroundOpacity"`
|
||||
// Anime
|
||||
SmallerEpisodeCarouselSize bool `gorm:"column:smaller_episode_carousel_size" json:"smallerEpisodeCarouselSize"`
|
||||
// Library Screen (Anime & Manga)
|
||||
// LibraryScreenBannerType: "dynamic", "custom"
|
||||
LibraryScreenBannerType string `gorm:"column:library_screen_banner_type" json:"libraryScreenBannerType"`
|
||||
LibraryScreenCustomBannerImage string `gorm:"column:library_screen_custom_banner_image" json:"libraryScreenCustomBannerImage"`
|
||||
LibraryScreenCustomBannerPosition string `gorm:"column:library_screen_custom_banner_position" json:"libraryScreenCustomBannerPosition"`
|
||||
LibraryScreenCustomBannerOpacity int `gorm:"column:library_screen_custom_banner_opacity" json:"libraryScreenCustomBannerOpacity"`
|
||||
DisableLibraryScreenGenreSelector bool `gorm:"column:disable_library_screen_genre_selector" json:"disableLibraryScreenGenreSelector"`
|
||||
|
||||
LibraryScreenCustomBackgroundBlur string `gorm:"column:library_screen_custom_background_blur" json:"libraryScreenCustomBackgroundBlur"`
|
||||
EnableMediaPageBlurredBackground bool `gorm:"column:enable_media_page_blurred_background" json:"enableMediaPageBlurredBackground"`
|
||||
DisableSidebarTransparency bool `gorm:"column:disable_sidebar_transparency" json:"disableSidebarTransparency"`
|
||||
UseLegacyEpisodeCard bool `gorm:"column:use_legacy_episode_card" json:"useLegacyEpisodeCard"` // DEPRECATED
|
||||
DisableCarouselAutoScroll bool `gorm:"column:disable_carousel_auto_scroll" json:"disableCarouselAutoScroll"`
|
||||
|
||||
// v2.6+
|
||||
MediaPageBannerType string `gorm:"column:media_page_banner_type" json:"mediaPageBannerType"`
|
||||
MediaPageBannerSize string `gorm:"column:media_page_banner_size" json:"mediaPageBannerSize"`
|
||||
MediaPageBannerInfoBoxSize string `gorm:"column:media_page_banner_info_box_size" json:"mediaPageBannerInfoBoxSize"`
|
||||
|
||||
// v2.7+
|
||||
ShowEpisodeCardAnimeInfo bool `gorm:"column:show_episode_card_anime_info" json:"showEpisodeCardAnimeInfo"`
|
||||
ContinueWatchingDefaultSorting string `gorm:"column:continue_watching_default_sorting" json:"continueWatchingDefaultSorting"`
|
||||
AnimeLibraryCollectionDefaultSorting string `gorm:"column:anime_library_collection_default_sorting" json:"animeLibraryCollectionDefaultSorting"`
|
||||
MangaLibraryCollectionDefaultSorting string `gorm:"column:manga_library_collection_default_sorting" json:"mangaLibraryCollectionDefaultSorting"`
|
||||
ShowAnimeUnwatchedCount bool `gorm:"column:show_anime_unwatched_count" json:"showAnimeUnwatchedCount"`
|
||||
ShowMangaUnreadCount bool `gorm:"column:show_manga_unread_count" json:"showMangaUnreadCount"`
|
||||
|
||||
// v2.8+
|
||||
HideEpisodeCardDescription bool `gorm:"column:hide_episode_card_description" json:"hideEpisodeCardDescription"`
|
||||
HideDownloadedEpisodeCardFilename bool `gorm:"column:hide_downloaded_episode_card_filename" json:"hideDownloadedEpisodeCardFilename"`
|
||||
CustomCSS string `gorm:"column:custom_css" json:"customCSS"`
|
||||
MobileCustomCSS string `gorm:"column:mobile_custom_css" json:"mobileCustomCSS"`
|
||||
|
||||
// v2.9+
|
||||
UnpinnedMenuItems StringSlice `gorm:"column:unpinned_menu_items;type:text" json:"unpinnedMenuItems"`
|
||||
}
|
||||
|
||||
// +---------------------+
|
||||
// | Playlist |
|
||||
// +---------------------+
|
||||
|
||||
type PlaylistEntry struct {
|
||||
BaseModel
|
||||
Name string `gorm:"column:name" json:"name"`
|
||||
Value []byte `gorm:"column:value" json:"value"`
|
||||
}
|
||||
|
||||
// +------------------------+
|
||||
// | Chapter Download Queue |
|
||||
// +------------------------+
|
||||
|
||||
type ChapterDownloadQueueItem struct {
|
||||
BaseModel
|
||||
Provider string `gorm:"column:provider" json:"provider"`
|
||||
MediaID int `gorm:"column:media_id" json:"mediaId"`
|
||||
ChapterID string `gorm:"column:chapter_id" json:"chapterId"`
|
||||
ChapterNumber string `gorm:"column:chapter_number" json:"chapterNumber"`
|
||||
PageData []byte `gorm:"column:page_data" json:"pageData"` // Contains map of page index to page details
|
||||
Status string `gorm:"column:status" json:"status"`
|
||||
}
|
||||
|
||||
// +---------------------+
|
||||
// | MediaStream |
|
||||
// +---------------------+
|
||||
|
||||
type MediastreamSettings struct {
|
||||
BaseModel
|
||||
// DEVNOTE: Should really be "Enabled"
|
||||
TranscodeEnabled bool `gorm:"column:transcode_enabled" json:"transcodeEnabled"`
|
||||
TranscodeHwAccel string `gorm:"column:transcode_hw_accel" json:"transcodeHwAccel"`
|
||||
TranscodeThreads int `gorm:"column:transcode_threads" json:"transcodeThreads"`
|
||||
TranscodePreset string `gorm:"column:transcode_preset" json:"transcodePreset"`
|
||||
DisableAutoSwitchToDirectPlay bool `gorm:"column:disable_auto_switch_to_direct_play" json:"disableAutoSwitchToDirectPlay"`
|
||||
DirectPlayOnly bool `gorm:"column:direct_play_only" json:"directPlayOnly"`
|
||||
PreTranscodeEnabled bool `gorm:"column:pre_transcode_enabled" json:"preTranscodeEnabled"`
|
||||
PreTranscodeLibraryDir string `gorm:"column:pre_transcode_library_dir" json:"preTranscodeLibraryDir"`
|
||||
FfmpegPath string `gorm:"column:ffmpeg_path" json:"ffmpegPath"`
|
||||
FfprobePath string `gorm:"column:ffprobe_path" json:"ffprobePath"`
|
||||
// v2.2+
|
||||
TranscodeHwAccelCustomSettings string `gorm:"column:transcode_hw_accel_custom_settings" json:"transcodeHwAccelCustomSettings"`
|
||||
|
||||
//TranscodeTempDir string `gorm:"column:transcode_temp_dir" json:"transcodeTempDir"` // DEPRECATED
|
||||
}
|
||||
|
||||
// +---------------------+
|
||||
// | TorrentStream |
|
||||
// +---------------------+
|
||||
|
||||
type TorrentstreamSettings struct {
|
||||
BaseModel
|
||||
Enabled bool `gorm:"column:enabled" json:"enabled"`
|
||||
AutoSelect bool `gorm:"column:auto_select" json:"autoSelect"`
|
||||
PreferredResolution string `gorm:"column:preferred_resolution" json:"preferredResolution"`
|
||||
DisableIPV6 bool `gorm:"column:disable_ipv6" json:"disableIPV6"`
|
||||
DownloadDir string `gorm:"column:download_dir" json:"downloadDir"`
|
||||
AddToLibrary bool `gorm:"column:add_to_library" json:"addToLibrary"`
|
||||
TorrentClientHost string `gorm:"column:torrent_client_host" json:"torrentClientHost"`
|
||||
TorrentClientPort int `gorm:"column:torrent_client_port" json:"torrentClientPort"`
|
||||
StreamingServerHost string `gorm:"column:streaming_server_host" json:"streamingServerHost"`
|
||||
StreamingServerPort int `gorm:"column:streaming_server_port" json:"streamingServerPort"`
|
||||
//FallbackToTorrentStreamingView bool `gorm:"column:fallback_to_torrent_streaming_view" json:"fallbackToTorrentStreamingView"` // DEPRECATED
|
||||
IncludeInLibrary bool `gorm:"column:include_in_library" json:"includeInLibrary"`
|
||||
// v2.6+
|
||||
StreamUrlAddress string `gorm:"column:stream_url_address" json:"streamUrlAddress"`
|
||||
// v2.7+
|
||||
SlowSeeding bool `gorm:"column:slow_seeding" json:"slowSeeding"`
|
||||
}
|
||||
|
||||
type TorrentstreamHistory struct {
|
||||
BaseModel
|
||||
MediaId int `gorm:"column:media_id" json:"mediaId"`
|
||||
Torrent []byte `gorm:"column:torrent" json:"torrent"`
|
||||
}
|
||||
|
||||
// +---------------------+
|
||||
// | Filler |
|
||||
// +---------------------+
|
||||
|
||||
type MediaFiller struct {
|
||||
BaseModel
|
||||
Provider string `gorm:"column:provider" json:"provider"`
|
||||
Slug string `gorm:"column:slug" json:"slug"`
|
||||
MediaID int `gorm:"column:media_id" json:"mediaId"`
|
||||
LastFetchedAt time.Time `gorm:"column:last_fetched_at" json:"lastFetchedAt"`
|
||||
Data []byte `gorm:"column:data" json:"data"`
|
||||
}
|
||||
|
||||
// +---------------------+
|
||||
// | Manga |
|
||||
// +---------------------+
|
||||
|
||||
type MangaMapping struct {
|
||||
BaseModel
|
||||
Provider string `gorm:"column:provider" json:"provider"`
|
||||
MediaID int `gorm:"column:media_id" json:"mediaId"`
|
||||
MangaID string `gorm:"column:manga_id" json:"mangaId"` // ID from search result, used to fetch chapters
|
||||
}
|
||||
|
||||
type MangaChapterContainer struct {
|
||||
BaseModel
|
||||
Provider string `gorm:"column:provider" json:"provider"`
|
||||
MediaID int `gorm:"column:media_id" json:"mediaId"`
|
||||
ChapterID string `gorm:"column:chapter_id" json:"chapterId"`
|
||||
Data []byte `gorm:"column:data" json:"data"`
|
||||
}
|
||||
|
||||
// +---------------------+
|
||||
// | Online streaming |
|
||||
// +---------------------+
|
||||
|
||||
type OnlinestreamMapping struct {
|
||||
BaseModel
|
||||
Provider string `gorm:"column:provider" json:"provider"`
|
||||
MediaID int `gorm:"column:media_id" json:"mediaId"`
|
||||
AnimeID string `gorm:"column:anime_id" json:"anime_id"` // ID from search result, used to fetch episodes
|
||||
}
|
||||
|
||||
// +---------------------+
|
||||
// | Debrid |
|
||||
// +---------------------+
|
||||
|
||||
type DebridSettings struct {
|
||||
BaseModel
|
||||
Enabled bool `gorm:"column:enabled" json:"enabled"`
|
||||
Provider string `gorm:"column:provider" json:"provider"`
|
||||
ApiKey string `gorm:"column:api_key" json:"apiKey"`
|
||||
//FallbackToDebridStreamingView bool `gorm:"column:fallback_to_debrid_streaming_view" json:"fallbackToDebridStreamingView"` // DEPRECATED
|
||||
IncludeDebridStreamInLibrary bool `gorm:"column:include_debrid_stream_in_library" json:"includeDebridStreamInLibrary"`
|
||||
StreamAutoSelect bool `gorm:"column:stream_auto_select" json:"streamAutoSelect"`
|
||||
StreamPreferredResolution string `gorm:"column:stream_preferred_resolution" json:"streamPreferredResolution"`
|
||||
}
|
||||
|
||||
type DebridTorrentItem struct {
|
||||
BaseModel
|
||||
TorrentItemID string `gorm:"column:torrent_item_id" json:"torrentItemId"`
|
||||
Destination string `gorm:"column:destination" json:"destination"`
|
||||
Provider string `gorm:"column:provider" json:"provider"`
|
||||
MediaId int `gorm:"column:media_id" json:"mediaId"`
|
||||
}
|
||||
|
||||
// +---------------------+
|
||||
// | Plugin |
|
||||
// +---------------------+
|
||||
|
||||
type PluginData struct {
|
||||
BaseModel
|
||||
PluginID string `gorm:"column:plugin_id;index" json:"pluginId"`
|
||||
Data []byte `gorm:"column:data" json:"data"`
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type StringSlice []string
|
||||
|
||||
func (o *StringSlice) Scan(src interface{}) error {
|
||||
str, ok := src.(string)
|
||||
if !ok {
|
||||
return errors.New("src value cannot cast to string")
|
||||
}
|
||||
*o = strings.Split(str, ",")
|
||||
return nil
|
||||
}
|
||||
func (o StringSlice) Value() (driver.Value, error) {
|
||||
if len(o) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return strings.Join(o, ","), nil
|
||||
}
|
||||
93
seanime-2.9.10/internal/database/models/models_helper.go
Normal file
93
seanime-2.9.10/internal/database/models/models_helper.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package models
|
||||
|
||||
func (s *Settings) GetMediaPlayer() *MediaPlayerSettings {
|
||||
if s == nil || s.MediaPlayer == nil {
|
||||
return &MediaPlayerSettings{}
|
||||
}
|
||||
return s.MediaPlayer
|
||||
}
|
||||
|
||||
func (s *Settings) GetTorrent() *TorrentSettings {
|
||||
if s == nil || s.Torrent == nil {
|
||||
return &TorrentSettings{}
|
||||
}
|
||||
return s.Torrent
|
||||
}
|
||||
|
||||
func (s *Settings) GetAnilist() *AnilistSettings {
|
||||
if s == nil || s.Anilist == nil {
|
||||
return &AnilistSettings{}
|
||||
}
|
||||
return s.Anilist
|
||||
}
|
||||
|
||||
func (s *Settings) GetManga() *MangaSettings {
|
||||
if s == nil || s.Manga == nil {
|
||||
return &MangaSettings{}
|
||||
}
|
||||
return s.Manga
|
||||
}
|
||||
|
||||
func (s *Settings) GetLibrary() *LibrarySettings {
|
||||
if s == nil || s.Library == nil {
|
||||
return &LibrarySettings{}
|
||||
}
|
||||
return s.Library
|
||||
}
|
||||
|
||||
func (s *Settings) GetListSync() *ListSyncSettings {
|
||||
if s == nil || s.ListSync == nil {
|
||||
return &ListSyncSettings{}
|
||||
}
|
||||
return s.ListSync
|
||||
}
|
||||
|
||||
func (s *Settings) GetAutoDownloader() *AutoDownloaderSettings {
|
||||
if s == nil || s.AutoDownloader == nil {
|
||||
return &AutoDownloaderSettings{}
|
||||
}
|
||||
return s.AutoDownloader
|
||||
}
|
||||
|
||||
func (s *Settings) GetDiscord() *DiscordSettings {
|
||||
if s == nil || s.Discord == nil {
|
||||
return &DiscordSettings{}
|
||||
}
|
||||
return s.Discord
|
||||
}
|
||||
|
||||
func (s *Settings) GetNotifications() *NotificationSettings {
|
||||
if s == nil || s.Notifications == nil {
|
||||
return &NotificationSettings{}
|
||||
}
|
||||
return s.Notifications
|
||||
}
|
||||
|
||||
func (s *Settings) GetNakama() *NakamaSettings {
|
||||
if s == nil || s.Nakama == nil {
|
||||
return &NakamaSettings{}
|
||||
}
|
||||
return s.Nakama
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
func (s *Settings) GetSensitiveValues() []string {
|
||||
if s == nil {
|
||||
return []string{}
|
||||
}
|
||||
return []string{
|
||||
s.GetMediaPlayer().VlcPassword,
|
||||
s.GetTorrent().QBittorrentPassword,
|
||||
s.GetTorrent().TransmissionPassword,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DebridSettings) GetSensitiveValues() []string {
|
||||
if s == nil {
|
||||
return []string{}
|
||||
}
|
||||
return []string{
|
||||
s.ApiKey,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user