Change own DbTable implementation for Gorm
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,5 +3,6 @@ findings.txt
|
|||||||
test.txt
|
test.txt
|
||||||
h.html
|
h.html
|
||||||
*.sqlite
|
*.sqlite
|
||||||
|
*.bak
|
||||||
/bin
|
/bin
|
||||||
*.exe
|
*.exe
|
||||||
@@ -66,13 +66,7 @@ func open(url string) error {
|
|||||||
|
|
||||||
func Close(db *database.Manager) {
|
func Close(db *database.Manager) {
|
||||||
fmt.Println("Attempting to save and close DB")
|
fmt.Println("Attempting to save and close DB")
|
||||||
err := db.Save()
|
err := db.Close()
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = db.Close()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
|||||||
7
go.mod
7
go.mod
@@ -6,3 +6,10 @@ require (
|
|||||||
github.com/mattn/go-sqlite3 v1.14.22
|
github.com/mattn/go-sqlite3 v1.14.22
|
||||||
golang.org/x/text v0.14.0
|
golang.org/x/text v0.14.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
|
gorm.io/driver/sqlite v1.5.5 // indirect
|
||||||
|
gorm.io/gorm v1.25.10 // indirect
|
||||||
|
)
|
||||||
|
|||||||
8
go.sum
8
go.sum
@@ -1,4 +1,12 @@
|
|||||||
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
|
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
gorm.io/driver/sqlite v1.5.5 h1:7MDMtUZhV065SilG62E0MquljeArQZNfJnjd9i9gx3E=
|
||||||
|
gorm.io/driver/sqlite v1.5.5/go.mod h1:6NgQ7sQWAIFsPrJJl1lSNSu2TABh0ZZ/zm5fosATavE=
|
||||||
|
gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
|
||||||
|
gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||||
|
|||||||
@@ -1,57 +1,21 @@
|
|||||||
package database
|
package database
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Chapter struct {
|
type Chapter struct {
|
||||||
Id int
|
Id int `gorm:"primary_key;AUTO_INCREMENT"`
|
||||||
MangaId int
|
|
||||||
Url string
|
Url string
|
||||||
Name string
|
Name string
|
||||||
Number string
|
Number string
|
||||||
TimeStampUnix int64
|
TimeStampUnix int64
|
||||||
|
MangaId int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewChapter(id int, mangaId int, url string, name string, number string, timeStampUnix int64) Chapter {
|
func NewChapter(id int, mangaId int, url string, name string, number string, timeStampUnix int64) Chapter {
|
||||||
return Chapter{
|
return Chapter{
|
||||||
Id: id,
|
Id: id,
|
||||||
MangaId: mangaId,
|
|
||||||
Url: url,
|
Url: url,
|
||||||
Name: name,
|
Name: name,
|
||||||
Number: number,
|
Number: number,
|
||||||
TimeStampUnix: timeStampUnix,
|
TimeStampUnix: timeStampUnix,
|
||||||
|
MangaId: mangaId,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateChapter(db *sql.DB, c *Chapter) error {
|
|
||||||
_, err := db.Exec("UPDATE Chapter set Name = ?, Url = ?, Number = ?, TimeStampUnixEpoch = ? where ID = ?", c.Name, c.Url, c.Number, c.TimeStampUnix, c.Id)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func insertChapter(db *sql.DB, c *Chapter) error {
|
|
||||||
_, err := db.Exec("INSERT INTO Chapter(ID, MangaID, Url, Name, Number, TimeStampUnixEpoch) VALUES (?, ?, ?, ?, ?, ?)", c.Id, c.MangaId, c.Url, c.Name, c.Number, c.TimeStampUnix)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadChapters(db *sql.DB) (map[int]Chapter, error) {
|
|
||||||
rows, err := db.Query("SELECT Id, MangaID, Url, Name, Number, TimeStampUnixEpoch FROM Chapter")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
res := make(map[int]Chapter)
|
|
||||||
|
|
||||||
for rows.Next() {
|
|
||||||
chapter := Chapter{}
|
|
||||||
if err = rows.Scan(&chapter.Id, &chapter.MangaId, &chapter.Url, &chapter.Name, &chapter.Number, &chapter.TimeStampUnix); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
res[chapter.Id] = chapter
|
|
||||||
}
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteChapter(db *sql.DB, key int) error {
|
|
||||||
_, err := db.Exec("DELETE from Chapter where ID = ?", key)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
create table if not exists Manga (
|
|
||||||
ID integer not null primary key,
|
|
||||||
Title text,
|
|
||||||
TimeStampUnixEpoch integer not null,
|
|
||||||
Thumbnail blob null,
|
|
||||||
LatestAvailableChapter text
|
|
||||||
);
|
|
||||||
|
|
||||||
create table if not exists Chapter (
|
|
||||||
ID integer not null primary key,
|
|
||||||
MangaID integer not null,
|
|
||||||
Url text not null,
|
|
||||||
Name text null,
|
|
||||||
Number text null,
|
|
||||||
TimeStampUnixEpoch integer not null,
|
|
||||||
foreign key(MangaID) references Manga(ID)
|
|
||||||
);
|
|
||||||
|
|
||||||
create table if not exists Setting (
|
|
||||||
Name text not null primary key,
|
|
||||||
Value text,
|
|
||||||
DefaultValue text not null
|
|
||||||
);
|
|
||||||
@@ -1,115 +1,59 @@
|
|||||||
package database
|
package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
|
||||||
_ "embed"
|
_ "embed"
|
||||||
"errors"
|
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
"gorm.io/driver/sqlite"
|
||||||
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
ConnectionString string
|
ConnectionString string
|
||||||
db *sql.DB
|
Db *gorm.DB
|
||||||
Mangas DbTable[int, Manga]
|
|
||||||
Chapters DbTable[int, Chapter]
|
|
||||||
Settings DbTable[string, Setting]
|
|
||||||
CreateIfNotExists bool
|
CreateIfNotExists bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDatabase(connectionString string, createIfNotExists bool) Manager {
|
func NewDatabase(connectionString string, createIfNotExists bool) Manager {
|
||||||
return Manager{
|
return Manager{
|
||||||
ConnectionString: connectionString,
|
ConnectionString: connectionString,
|
||||||
db: nil,
|
Db: nil,
|
||||||
Mangas: NewDbTable(updateManga, insertManga, loadMangas, deleteManga),
|
|
||||||
Chapters: NewDbTable(updateChapter, insertChapter, loadChapters, deleteChapter),
|
|
||||||
Settings: NewDbTable(updateSetting, insertSetting, loadSettings, deleteSetting),
|
|
||||||
CreateIfNotExists: createIfNotExists,
|
CreateIfNotExists: createIfNotExists,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbMgr *Manager) Open() error {
|
func (dbMgr *Manager) Open() error {
|
||||||
db, err := sql.Open("sqlite3", dbMgr.ConnectionString)
|
db, err := gorm.Open(sqlite.Open(dbMgr.ConnectionString), &gorm.Config{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
dbMgr.db = db
|
dbMgr.Db = db
|
||||||
if dbMgr.CreateIfNotExists {
|
if dbMgr.CreateIfNotExists {
|
||||||
err = dbMgr.createDatabaseIfNotExists()
|
err = dbMgr.createDatabaseIfNotExists()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = dbMgr.load()
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbMgr *Manager) Close() error {
|
func (dbMgr *Manager) Close() error {
|
||||||
err := dbMgr.db.Close()
|
sql, err := dbMgr.Db.DB()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
err = sql.Close()
|
||||||
dbMgr.db = nil
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
dbMgr.Db = nil
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbMgr *Manager) Delete(mangaId int) error {
|
func (dbMgr *Manager) Delete(mangaId int) {
|
||||||
dbMgr.Mangas.Get(mangaId)
|
dbMgr.Db.Delete(&Manga{}, mangaId)
|
||||||
err := dbMgr.Mangas.Delete(dbMgr.db, mangaId)
|
|
||||||
if err != nil && !errors.Is(err, IgnoreDeleteError{}) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
chapters := dbMgr.Chapters.All()
|
|
||||||
for i, chapter := range chapters {
|
|
||||||
if chapter.MangaId == mangaId {
|
|
||||||
err := dbMgr.Chapters.Delete(dbMgr.db, i)
|
|
||||||
if err != nil && !errors.Is(err, IgnoreDeleteError{}) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbMgr *Manager) Save() error {
|
|
||||||
err := dbMgr.Mangas.Save(dbMgr.db)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = dbMgr.Chapters.Save(dbMgr.db)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return dbMgr.Settings.Save(dbMgr.db)
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:embed createDb.sql
|
|
||||||
var createSql string
|
|
||||||
|
|
||||||
func (dbMgr *Manager) createDatabaseIfNotExists() error {
|
func (dbMgr *Manager) createDatabaseIfNotExists() error {
|
||||||
_, err := dbMgr.db.Exec(createSql)
|
err := dbMgr.Db.AutoMigrate(&Manga{}, &Chapter{}, &Setting{})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbMgr *Manager) load() error {
|
|
||||||
err := dbMgr.Chapters.Load(dbMgr.db)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = dbMgr.Mangas.Load(dbMgr.db)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = dbMgr.Settings.Load(dbMgr.db)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
initSettings(&dbMgr.Settings)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,16 +1,13 @@
|
|||||||
package database
|
package database
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"database/sql"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Manga struct {
|
type Manga struct {
|
||||||
Id int
|
Id int `gorm:"primary_key;AUTO_INCREMENT"`
|
||||||
Title string
|
Title string
|
||||||
TimeStampUnix int64
|
TimeStampUnix int64
|
||||||
Thumbnail *bytes.Buffer
|
Thumbnail []byte
|
||||||
LastChapterNum string
|
LastChapterNum string
|
||||||
|
Chapters []Chapter
|
||||||
|
//`gorm:"foreignkey:MangaID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewManga(id int, title string, timeStampUnix int64) Manga {
|
func NewManga(id int, title string, timeStampUnix int64) Manga {
|
||||||
@@ -23,12 +20,10 @@ func NewManga(id int, title string, timeStampUnix int64) Manga {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetLatestChapter TODO: Cache this somehow
|
// GetLatestChapter TODO: Cache this somehow
|
||||||
func (m *Manga) GetLatestChapter(chapters *DbTable[int, Chapter]) (*Chapter, bool) {
|
func (m *Manga) GetLatestChapter() (*Chapter, bool) {
|
||||||
c := chapters.All()
|
|
||||||
|
|
||||||
highest := int64(0)
|
highest := int64(0)
|
||||||
index := 0
|
index := 0
|
||||||
for i, chapter := range c {
|
for i, chapter := range m.Chapters {
|
||||||
if chapter.MangaId == m.Id && highest < chapter.TimeStampUnix {
|
if chapter.MangaId == m.Id && highest < chapter.TimeStampUnix {
|
||||||
highest = chapter.TimeStampUnix
|
highest = chapter.TimeStampUnix
|
||||||
index = i
|
index = i
|
||||||
@@ -39,58 +34,14 @@ func (m *Manga) GetLatestChapter(chapters *DbTable[int, Chapter]) (*Chapter, boo
|
|||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
return &c[index], true
|
return &m.Chapters[index], true
|
||||||
}
|
|
||||||
|
//result := db.Where("manga.id = ?", m.Id).Order("TimeStampUnix desc").Take(&chapter)
|
||||||
func updateManga(db *sql.DB, m *Manga) error {
|
//if result.Error != nil && !errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||||
const cmd = "UPDATE Manga set Title = ?, TimeStampUnixEpoch = ?, Thumbnail = ?, LatestAvailableChapter = ? WHERE ID = ?"
|
// return &chapter, true, result.Error
|
||||||
var err error
|
//} else if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||||
if m.Thumbnail == nil {
|
// return &chapter, false, nil
|
||||||
_, err = db.Exec(cmd, m.Title, m.TimeStampUnix, nil, m.LastChapterNum, m.Id)
|
//} else {
|
||||||
|
// return &chapter, true, nil
|
||||||
} else {
|
//}
|
||||||
_, err = db.Exec(cmd, m.Title, m.TimeStampUnix, m.Thumbnail.Bytes(), m.LastChapterNum, m.Id)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func insertManga(db *sql.DB, manga *Manga) error {
|
|
||||||
const cmd = "INSERT INTO Manga(ID, Title, TimeStampUnixEpoch, Thumbnail, LatestAvailableChapter) values(?, ?, ?, ?, ?)"
|
|
||||||
var err error
|
|
||||||
if manga.Thumbnail == nil {
|
|
||||||
_, err = db.Exec(cmd, manga.Id, manga.Title, manga.TimeStampUnix, nil, manga.LastChapterNum)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
_, err = db.Exec(cmd, manga.Id, manga.Title, manga.TimeStampUnix, manga.Thumbnail.Bytes(), manga.LastChapterNum)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadMangas(db *sql.DB) (map[int]Manga, error) {
|
|
||||||
rows, err := db.Query("SELECT Id, Title, TimeStampUnixEpoch, Thumbnail, LatestAvailableChapter FROM Manga")
|
|
||||||
if err != nil {
|
|
||||||
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
res := make(map[int]Manga)
|
|
||||||
|
|
||||||
for rows.Next() {
|
|
||||||
manga := Manga{}
|
|
||||||
var thumbnail []byte
|
|
||||||
if err = rows.Scan(&manga.Id, &manga.Title, &manga.TimeStampUnix, &thumbnail, &manga.LastChapterNum); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(thumbnail) != 0 {
|
|
||||||
manga.Thumbnail = bytes.NewBuffer(thumbnail)
|
|
||||||
}
|
|
||||||
|
|
||||||
res[manga.Id] = manga
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteManga(db *sql.DB, key int) error {
|
|
||||||
_, err := db.Exec("DELETE from Manga where ID = ?", key)
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
package database
|
package database
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Setting struct {
|
type Setting struct {
|
||||||
Name string
|
Name string `gorm:"PRIMARY_KEY"`
|
||||||
Value string
|
Value string
|
||||||
Default string
|
Default string
|
||||||
}
|
}
|
||||||
@@ -18,57 +14,14 @@ func NewSetting(name string, defaultValue string) Setting {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func initSettings(settings *DbTable[string, Setting]) {
|
//func initSettings(settings *DbTable[string, Setting]) {
|
||||||
addSettingIfNotExists("theme", "white", settings)
|
// addSettingIfNotExists("theme", "white", settings)
|
||||||
addSettingIfNotExists("order", "title", settings)
|
// addSettingIfNotExists("order", "title", settings)
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
func addSettingIfNotExists(name string, value string, settings *DbTable[string, Setting]) {
|
//func addSettingIfNotExists(name string, value string, settings *DbTable[string, Setting]) {
|
||||||
_, exists := settings.Get(name)
|
// _, exists := settings.Get(name)
|
||||||
if !exists {
|
// if !exists {
|
||||||
settings.Set(name, NewSetting(name, value))
|
// settings.Set(name, NewSetting(name, value))
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
func updateSetting(db *sql.DB, s *Setting) error {
|
|
||||||
const cmd = "UPDATE Setting set Value = ? WHERE Name = ?"
|
|
||||||
_, err := db.Exec(cmd, s.Value, s.Name)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func insertSetting(db *sql.DB, s *Setting) error {
|
|
||||||
const cmd = "INSERT INTO Setting(Name, Value, DefaultValue) VALUES(?, ?, ?)"
|
|
||||||
_, err := db.Exec(cmd, s.Name, s.Value, s.Default)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadSettings(db *sql.DB) (map[string]Setting, error) {
|
|
||||||
const cmd = "SELECT Name, Value, DefaultValue from Setting"
|
|
||||||
rows, err := db.Query(cmd)
|
|
||||||
|
|
||||||
res := make(map[string]Setting)
|
|
||||||
|
|
||||||
for rows.Next() {
|
|
||||||
setting := Setting{}
|
|
||||||
if err = rows.Scan(&setting.Name, &setting.Value, &setting.Default); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
res[setting.Name] = setting
|
|
||||||
}
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
type IgnoreDeleteError struct{}
|
|
||||||
|
|
||||||
func (m IgnoreDeleteError) Error() string {
|
|
||||||
return "Should ignore deletion"
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteSetting(db *sql.DB, key string) error {
|
|
||||||
const cmd = "UPDATE Setting set Value = DefaultValue WHERE Name = ?"
|
|
||||||
_, err := db.Exec(cmd, key)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return IgnoreDeleteError{}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,156 +0,0 @@
|
|||||||
package database
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DbStatus uint8
|
|
||||||
|
|
||||||
const (
|
|
||||||
New DbStatus = iota
|
|
||||||
Loaded
|
|
||||||
Updated
|
|
||||||
)
|
|
||||||
|
|
||||||
type DbTable[K comparable, T any] struct {
|
|
||||||
mutex sync.Mutex
|
|
||||||
items map[K]T
|
|
||||||
updated map[K]DbStatus
|
|
||||||
updateFunc func(db *sql.DB, value *T) error
|
|
||||||
insertFunc func(db *sql.DB, value *T) error
|
|
||||||
loadFunc func(db *sql.DB) (map[K]T, error)
|
|
||||||
deleteFunc func(db *sql.DB, key K) error
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDbTable[K comparable, T any](updateFunc func(db *sql.DB, value *T) error,
|
|
||||||
insertFunc func(db *sql.DB, value *T) error,
|
|
||||||
loadFunc func(db *sql.DB) (map[K]T, error),
|
|
||||||
deleteFunc func(db *sql.DB, key K) error,
|
|
||||||
) DbTable[K, T] {
|
|
||||||
return DbTable[K, T]{
|
|
||||||
mutex: sync.Mutex{},
|
|
||||||
items: make(map[K]T),
|
|
||||||
updated: make(map[K]DbStatus),
|
|
||||||
updateFunc: updateFunc,
|
|
||||||
insertFunc: insertFunc,
|
|
||||||
loadFunc: loadFunc,
|
|
||||||
deleteFunc: deleteFunc,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DbTable[K, T]) Get(key K) (T, bool) {
|
|
||||||
d.mutex.Lock()
|
|
||||||
defer d.mutex.Unlock()
|
|
||||||
val, ok := d.items[key]
|
|
||||||
return val, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DbTable[K, T]) Set(key K, new T) {
|
|
||||||
d.mutex.Lock()
|
|
||||||
defer d.mutex.Unlock()
|
|
||||||
val, ok := d.updated[key]
|
|
||||||
if ok && val == Loaded || val == Updated {
|
|
||||||
d.updated[key] = Updated
|
|
||||||
} else {
|
|
||||||
d.updated[key] = New
|
|
||||||
}
|
|
||||||
d.items[key] = new
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DbTable[K, T]) All() []T {
|
|
||||||
d.mutex.Lock()
|
|
||||||
defer d.mutex.Unlock()
|
|
||||||
res := make([]T, len(d.items))
|
|
||||||
counter := 0
|
|
||||||
for _, manga := range d.items {
|
|
||||||
res[counter] = manga
|
|
||||||
counter++
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DbTable[K, T]) Map() map[K]T {
|
|
||||||
d.mutex.Lock()
|
|
||||||
defer d.mutex.Unlock()
|
|
||||||
res := make(map[K]T, len(d.items))
|
|
||||||
for k, manga := range d.items {
|
|
||||||
res[k] = manga
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DbTable[K, T]) First(filter func(match T) bool) (key K, value T, ok bool) {
|
|
||||||
d.mutex.Lock()
|
|
||||||
defer d.mutex.Unlock()
|
|
||||||
|
|
||||||
for k, manga := range d.items {
|
|
||||||
if filter(manga) {
|
|
||||||
return k, manga, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return *new(K), *new(T), false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DbTable[K, T]) Where(filter func(match T) bool) map[K]T {
|
|
||||||
d.mutex.Lock()
|
|
||||||
defer d.mutex.Unlock()
|
|
||||||
res := make(map[K]T, len(d.items))
|
|
||||||
for k, manga := range d.items {
|
|
||||||
if filter(manga) {
|
|
||||||
res[k] = manga
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DbTable[K, T]) Delete(db *sql.DB, key K) error {
|
|
||||||
d.mutex.Lock()
|
|
||||||
defer d.mutex.Unlock()
|
|
||||||
err := d.deleteFunc(db, key)
|
|
||||||
if err == nil {
|
|
||||||
delete(d.items, key)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DbTable[K, T]) Save(db *sql.DB) error {
|
|
||||||
d.mutex.Lock()
|
|
||||||
defer d.mutex.Unlock()
|
|
||||||
for k, status := range d.updated {
|
|
||||||
switch status {
|
|
||||||
case Loaded:
|
|
||||||
continue
|
|
||||||
case Updated:
|
|
||||||
item := d.items[k]
|
|
||||||
err := d.updateFunc(db, &item)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
d.updated[k] = Loaded
|
|
||||||
case New:
|
|
||||||
item := d.items[k]
|
|
||||||
err := d.insertFunc(db, &item)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
d.updated[k] = Loaded
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DbTable[K, T]) Load(db *sql.DB) error {
|
|
||||||
d.mutex.Lock()
|
|
||||||
defer d.mutex.Unlock()
|
|
||||||
res, err := d.loadFunc(db)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
d.items = res
|
|
||||||
for k := range d.items {
|
|
||||||
d.updated[k] = Loaded
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -3,11 +3,13 @@ package server
|
|||||||
import (
|
import (
|
||||||
"cmp"
|
"cmp"
|
||||||
_ "embed"
|
_ "embed"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/pablu23/mangaGetter/internal/database"
|
"github.com/pablu23/mangaGetter/internal/database"
|
||||||
"github.com/pablu23/mangaGetter/internal/view"
|
"github.com/pablu23/mangaGetter/internal/view"
|
||||||
"golang.org/x/text/cases"
|
"golang.org/x/text/cases"
|
||||||
"golang.org/x/text/language"
|
"golang.org/x/text/language"
|
||||||
|
"gorm.io/gorm"
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
"slices"
|
"slices"
|
||||||
@@ -35,13 +37,21 @@ func (s *Server) HandleNew(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
func (s *Server) HandleMenu(w http.ResponseWriter, _ *http.Request) {
|
func (s *Server) HandleMenu(w http.ResponseWriter, _ *http.Request) {
|
||||||
tmpl := template.Must(view.GetViewTemplate(view.Menu))
|
tmpl := template.Must(view.GetViewTemplate(view.Menu))
|
||||||
all := s.DbMgr.Mangas.All()
|
var all []*database.Manga
|
||||||
|
_ = s.DbMgr.Db.Preload("Chapters").Find(&all)
|
||||||
l := len(all)
|
l := len(all)
|
||||||
mangaViewModels := make([]view.MangaViewModel, l)
|
mangaViewModels := make([]view.MangaViewModel, l)
|
||||||
counter := 0
|
counter := 0
|
||||||
|
|
||||||
n := time.Now().UnixNano()
|
n := time.Now().UnixNano()
|
||||||
|
|
||||||
|
var tmp []database.Setting
|
||||||
|
s.DbMgr.Db.Find(&tmp)
|
||||||
|
settings := make(map[string]database.Setting)
|
||||||
|
for _, m := range tmp {
|
||||||
|
settings[m.Name] = m
|
||||||
|
}
|
||||||
|
|
||||||
var thumbNs int64 = 0
|
var thumbNs int64 = 0
|
||||||
var titNs int64 = 0
|
var titNs int64 = 0
|
||||||
|
|
||||||
@@ -51,13 +61,13 @@ func (s *Server) HandleMenu(w http.ResponseWriter, _ *http.Request) {
|
|||||||
|
|
||||||
t1 := time.Now().UnixNano()
|
t1 := time.Now().UnixNano()
|
||||||
|
|
||||||
thumbnail, updated, err := s.LoadThumbnail(&manga)
|
thumbnail, updated, err := s.LoadThumbnail(manga)
|
||||||
//TODO: Add default picture instead of not showing Manga at all
|
//TODO: Add default picture instead of not showing Manga at all
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if updated {
|
if updated {
|
||||||
s.DbMgr.Mangas.Set(manga.Id, manga)
|
s.DbMgr.Db.Save(manga)
|
||||||
}
|
}
|
||||||
|
|
||||||
t2 := time.Now().UnixNano()
|
t2 := time.Now().UnixNano()
|
||||||
@@ -69,12 +79,12 @@ func (s *Server) HandleMenu(w http.ResponseWriter, _ *http.Request) {
|
|||||||
// This is very slow
|
// This is very slow
|
||||||
// TODO: put this into own Method
|
// TODO: put this into own Method
|
||||||
if manga.LastChapterNum == "" {
|
if manga.LastChapterNum == "" {
|
||||||
err, updated := s.UpdateLatestAvailableChapter(&manga)
|
err, updated := s.UpdateLatestAvailableChapter(manga)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
if updated {
|
if updated {
|
||||||
s.DbMgr.Mangas.Set(manga.Id, manga)
|
s.DbMgr.Db.Save(manga)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +92,7 @@ func (s *Server) HandleMenu(w http.ResponseWriter, _ *http.Request) {
|
|||||||
|
|
||||||
titNs += t2 - t1
|
titNs += t2 - t1
|
||||||
|
|
||||||
latestChapter, ok := manga.GetLatestChapter(&s.DbMgr.Chapters)
|
latestChapter, ok := manga.GetLatestChapter()
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -101,24 +111,23 @@ func (s *Server) HandleMenu(w http.ResponseWriter, _ *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Loading Thumbnails took %d ms\n", (thumbNs)/1000000)
|
fmt.Printf("Loading Thumbnails took %d ms\n", (thumbNs)/1000000)
|
||||||
fmt.Printf("Loading latest Chapter took %d ms\n", (titNs)/1000000)
|
fmt.Printf("Loading latest Chapters took %d ms\n", (titNs)/1000000)
|
||||||
|
|
||||||
nex := time.Now().UnixNano()
|
nex := time.Now().UnixNano()
|
||||||
fmt.Printf("Creating Viewmodels took %d ms\n", (nex-n)/1000000)
|
fmt.Printf("Creating Viewmodels took %d ms\n", (nex-n)/1000000)
|
||||||
|
|
||||||
n = time.Now().UnixNano()
|
n = time.Now().UnixNano()
|
||||||
|
|
||||||
order, ok := s.DbMgr.Settings.Get("order")
|
order, ok := settings["order"]
|
||||||
sort := order.Value
|
if !ok || order.Value == "title" {
|
||||||
if !ok || sort == "title" {
|
|
||||||
slices.SortStableFunc(mangaViewModels, func(a, b view.MangaViewModel) int {
|
slices.SortStableFunc(mangaViewModels, func(a, b view.MangaViewModel) int {
|
||||||
return cmp.Compare(a.Title, b.Title)
|
return cmp.Compare(a.Title, b.Title)
|
||||||
})
|
})
|
||||||
} else if sort == "chapter" {
|
} else if order.Value == "chapter" {
|
||||||
slices.SortStableFunc(mangaViewModels, func(a, b view.MangaViewModel) int {
|
slices.SortStableFunc(mangaViewModels, func(a, b view.MangaViewModel) int {
|
||||||
return cmp.Compare(b.Number, a.Number)
|
return cmp.Compare(b.Number, a.Number)
|
||||||
})
|
})
|
||||||
} else if sort == "last" {
|
} else if order.Value == "last" {
|
||||||
slices.SortStableFunc(mangaViewModels, func(a, b view.MangaViewModel) int {
|
slices.SortStableFunc(mangaViewModels, func(a, b view.MangaViewModel) int {
|
||||||
aT, err := time.Parse("15:04 (02-01-06)", a.LastTime)
|
aT, err := time.Parse("15:04 (02-01-06)", a.LastTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -136,7 +145,7 @@ func (s *Server) HandleMenu(w http.ResponseWriter, _ *http.Request) {
|
|||||||
fmt.Printf("Sorting took %d ms\n", (nex-n)/1000000)
|
fmt.Printf("Sorting took %d ms\n", (nex-n)/1000000)
|
||||||
|
|
||||||
menuViewModel := view.MenuViewModel{
|
menuViewModel := view.MenuViewModel{
|
||||||
Settings: s.DbMgr.Settings.Map(),
|
Settings: settings,
|
||||||
Mangas: mangaViewModels,
|
Mangas: mangaViewModels,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,22 +170,12 @@ func (s *Server) HandleDelete(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.DbMgr.Delete(mangaId)
|
s.DbMgr.Delete(mangaId)
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
|
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) HandleExit(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) HandleExit(w http.ResponseWriter, r *http.Request) {
|
||||||
err := s.DbMgr.Save()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
http.Redirect(w, r, "/curr", http.StatusTemporaryRedirect)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
|
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@@ -215,23 +214,25 @@ func (s *Server) HandleCurrent(w http.ResponseWriter, _ *http.Request) {
|
|||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
manga, ok := s.DbMgr.Mangas.Get(mangaId)
|
var manga database.Manga
|
||||||
if !ok {
|
result := s.DbMgr.Db.First(&manga, mangaId)
|
||||||
|
if result.Error != nil && errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||||
manga = database.NewManga(mangaId, title, time.Now().Unix())
|
manga = database.NewManga(mangaId, title, time.Now().Unix())
|
||||||
} else {
|
} else {
|
||||||
manga.TimeStampUnix = time.Now().Unix()
|
manga.TimeStampUnix = time.Now().Unix()
|
||||||
}
|
}
|
||||||
|
|
||||||
chapter, ok := s.DbMgr.Chapters.Get(chapterId)
|
var chapter database.Chapter
|
||||||
if !ok {
|
result = s.DbMgr.Db.First(&chapter, chapterId)
|
||||||
|
if result.Error != nil && errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||||
chapterNumberStr := strings.Replace(chapterName, "ch_", "", 1)
|
chapterNumberStr := strings.Replace(chapterName, "ch_", "", 1)
|
||||||
chapter = database.NewChapter(chapterId, manga.Id, s.CurrSubUrl, chapterName, chapterNumberStr, time.Now().Unix())
|
chapter = database.NewChapter(chapterId, mangaId, s.CurrSubUrl, chapterName, chapterNumberStr, time.Now().Unix())
|
||||||
} else {
|
} else {
|
||||||
chapter.TimeStampUnix = time.Now().Unix()
|
chapter.TimeStampUnix = time.Now().Unix()
|
||||||
}
|
}
|
||||||
|
|
||||||
s.DbMgr.Chapters.Set(chapterId, chapter)
|
s.DbMgr.Db.Save(&manga)
|
||||||
s.DbMgr.Mangas.Set(mangaId, manga)
|
s.DbMgr.Db.Save(&chapter)
|
||||||
|
|
||||||
err = tmpl.Execute(w, s.CurrViewModel)
|
err = tmpl.Execute(w, s.CurrViewModel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -251,7 +252,7 @@ func (s *Server) HandleImage(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "image/webp")
|
w.Header().Set("Content-Type", "image/webp")
|
||||||
_, err := w.Write(buf.Bytes())
|
_, err := w.Write(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
@@ -284,10 +285,6 @@ func (s *Server) HandleNext(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
if s.NextViewModel == nil || s.NextSubUrl == "" {
|
if s.NextViewModel == nil || s.NextSubUrl == "" {
|
||||||
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
|
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
|
||||||
err := s.DbMgr.Save()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,10 +312,6 @@ func (s *Server) HandlePrev(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
if s.PrevViewModel == nil || s.PrevSubUrl == "" {
|
if s.PrevViewModel == nil || s.PrevSubUrl == "" {
|
||||||
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
|
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
|
||||||
err := s.DbMgr.Save()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,14 +329,14 @@ func (s *Server) HandleSettingSet(w http.ResponseWriter, r *http.Request) {
|
|||||||
settingName := r.PathValue("setting")
|
settingName := r.PathValue("setting")
|
||||||
settingValue := r.PathValue("value")
|
settingValue := r.PathValue("value")
|
||||||
|
|
||||||
setting, ok := s.DbMgr.Settings.Get(settingName)
|
var setting database.Setting
|
||||||
if !ok {
|
res := s.DbMgr.Db.First(&setting, "name = ?", settingName)
|
||||||
s.DbMgr.Settings.Set(settingName, database.NewSetting(settingName, settingValue))
|
|
||||||
|
if res.Error != nil && errors.Is(res.Error, gorm.ErrRecordNotFound) {
|
||||||
|
set := database.NewSetting(settingName, settingValue)
|
||||||
|
s.DbMgr.Db.Save(&set)
|
||||||
} else {
|
} else {
|
||||||
if setting.Value != settingValue {
|
s.DbMgr.Db.Model(&setting).Update("value", settingValue)
|
||||||
setting.Value = settingValue
|
|
||||||
s.DbMgr.Settings.Set(settingName, setting)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
|
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
|
||||||
@@ -353,14 +346,14 @@ func (s *Server) HandleSetting(w http.ResponseWriter, r *http.Request) {
|
|||||||
settingName := r.PostFormValue("setting")
|
settingName := r.PostFormValue("setting")
|
||||||
settingValue := r.PostFormValue(settingName)
|
settingValue := r.PostFormValue(settingName)
|
||||||
|
|
||||||
setting, ok := s.DbMgr.Settings.Get(settingName)
|
var setting database.Setting
|
||||||
if !ok {
|
res := s.DbMgr.Db.First(&setting, "name = ?", settingName)
|
||||||
s.DbMgr.Settings.Set(settingName, database.NewSetting(settingName, settingValue))
|
|
||||||
|
if res.Error != nil && errors.Is(res.Error, gorm.ErrRecordNotFound) {
|
||||||
|
set := database.NewSetting(settingName, settingValue)
|
||||||
|
s.DbMgr.Db.Save(&set)
|
||||||
} else {
|
} else {
|
||||||
if setting.Value != settingValue {
|
s.DbMgr.Db.Model(&setting).Update("value", settingValue)
|
||||||
setting.Value = settingValue
|
|
||||||
s.DbMgr.Settings.Set(settingName, setting)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
|
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ type Server struct {
|
|||||||
CurrViewModel *view.ImageViewModel
|
CurrViewModel *view.ImageViewModel
|
||||||
NextViewModel *view.ImageViewModel
|
NextViewModel *view.ImageViewModel
|
||||||
|
|
||||||
ImageBuffers map[string]*bytes.Buffer
|
ImageBuffers map[string][]byte
|
||||||
Mutex *sync.Mutex
|
Mutex *sync.Mutex
|
||||||
|
|
||||||
NextSubUrl string
|
NextSubUrl string
|
||||||
@@ -38,7 +38,7 @@ type Server struct {
|
|||||||
|
|
||||||
func New(provider provider.Provider, db *database.Manager) *Server {
|
func New(provider provider.Provider, db *database.Manager) *Server {
|
||||||
s := Server{
|
s := Server{
|
||||||
ImageBuffers: make(map[string]*bytes.Buffer),
|
ImageBuffers: make(map[string][]byte),
|
||||||
Provider: provider,
|
Provider: provider,
|
||||||
DbMgr: db,
|
DbMgr: db,
|
||||||
Mutex: &sync.Mutex{},
|
Mutex: &sync.Mutex{},
|
||||||
@@ -61,16 +61,18 @@ func (s *Server) Start(port int) error {
|
|||||||
http.HandleFunc("POST /setting/", s.HandleSetting)
|
http.HandleFunc("POST /setting/", s.HandleSetting)
|
||||||
http.HandleFunc("GET /setting/set/{setting}/{value}", s.HandleSettingSet)
|
http.HandleFunc("GET /setting/set/{setting}/{value}", s.HandleSettingSet)
|
||||||
|
|
||||||
// Update Latest Chapter every 5 Minutes
|
// Update Latest Chapters every 5 Minutes
|
||||||
go func(s *Server) {
|
go func(s *Server) {
|
||||||
time.AfterFunc(time.Second*10, func() {
|
time.AfterFunc(time.Second*10, func() {
|
||||||
for _, m := range s.DbMgr.Mangas.All() {
|
var all []*database.Manga
|
||||||
err, updated := s.UpdateLatestAvailableChapter(&m)
|
s.DbMgr.Db.Find(&all)
|
||||||
|
for _, m := range all {
|
||||||
|
err, updated := s.UpdateLatestAvailableChapter(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
if updated {
|
if updated {
|
||||||
s.DbMgr.Mangas.Set(m.Id, m)
|
s.DbMgr.Db.Save(m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -78,13 +80,15 @@ func (s *Server) Start(port int) error {
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-time.After(time.Minute * 5):
|
case <-time.After(time.Minute * 5):
|
||||||
for _, m := range s.DbMgr.Mangas.All() {
|
var all []*database.Manga
|
||||||
err, updated := s.UpdateLatestAvailableChapter(&m)
|
s.DbMgr.Db.Find(&all)
|
||||||
|
for _, m := range all {
|
||||||
|
err, updated := s.UpdateLatestAvailableChapter(m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
if updated {
|
if updated {
|
||||||
s.DbMgr.Mangas.Set(m.Id, m)
|
s.DbMgr.Db.Save(m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -287,7 +291,7 @@ func (s *Server) AppendImagesToBuf(html string) ([]view.Image, error) {
|
|||||||
return images, nil
|
return images, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addFileToRam(url string) (*bytes.Buffer, error) {
|
func addFileToRam(url string) ([]byte, error) {
|
||||||
// Get the data
|
// Get the data
|
||||||
resp, err := http.Get(url)
|
resp, err := http.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -304,5 +308,5 @@ func addFileToRam(url string) (*bytes.Buffer, error) {
|
|||||||
|
|
||||||
// Write the body to file
|
// Write the body to file
|
||||||
_, err = io.Copy(buf, resp.Body)
|
_, err = io.Copy(buf, resp.Body)
|
||||||
return buf, err
|
return buf.Bytes(), err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user