Added saving of LatestAvailableChapter and updating it in goroutine every 5 Minutes, also Added filtering to menu

This commit is contained in:
Pablu23
2024-03-06 23:27:14 +01:00
parent ad1fcbc68a
commit 1377fd420e
7 changed files with 113 additions and 59 deletions

View File

@@ -8,10 +8,11 @@ That's, why I created this simple pre Loader, right now it's not really user-fri
a few more features a few more features
# Features that might get added: # Features that might get added:
- Manga / Chapter History
- Searchbar - Searchbar
- Better looking UI - Better looking UI
- Main Screen - Genres and Filter
- More Providers like Asuratoon
- Performance improvements
# Pretext # Pretext

View File

@@ -5,7 +5,6 @@ import (
"mangaGetter/internal/database" "mangaGetter/internal/database"
"mangaGetter/internal/provider" "mangaGetter/internal/provider"
"mangaGetter/internal/server" "mangaGetter/internal/server"
"net/http"
"os" "os"
"os/exec" "os/exec"
"os/signal" "os/signal"
@@ -34,17 +33,6 @@ func main() {
} }
}() }()
http.HandleFunc("/", s.HandleMenu)
http.HandleFunc("/new/", s.HandleNewQuery)
http.HandleFunc("/new/title/{title}/{chapter}", s.HandleNew)
http.HandleFunc("/current/", s.HandleCurrent)
http.HandleFunc("/img/{url}/", s.HandleImage)
http.HandleFunc("POST /next", s.HandleNext)
http.HandleFunc("POST /prev", s.HandlePrev)
http.HandleFunc("POST /exit", s.HandleExit)
http.HandleFunc("POST /delete", s.HandleDelete)
http.HandleFunc("/favicon.ico", s.HandleFavicon)
go func() { go func() {
time.Sleep(300 * time.Millisecond) time.Sleep(300 * time.Millisecond)
err := open("http://localhost:8000") err := open("http://localhost:8000")
@@ -53,11 +41,9 @@ func main() {
} }
}() }()
fmt.Println("Server starting...") err = s.Start()
err = http.ListenAndServe(":8000", nil)
if err != nil { if err != nil {
fmt.Println(err) panic(err)
return
} }
} }

View File

@@ -1,8 +1,9 @@
create table if not exists Manga ( create table if not exists Manga (
ID integer not null primary key, ID integer not null primary key,
Title text, Title text,
TimeStampUnixEpoch int, TimeStampUnixEpoch integer not null,
Thumbnail blob Thumbnail blob,
LatestAvailableChapter integer not null
); );
create table if not exists Chapter ( create table if not exists Chapter (
@@ -10,7 +11,7 @@ create table if not exists Chapter (
MangaID integer not null, MangaID integer not null,
Url text not null, Url text not null,
Name text null, Name text null,
Number int not null, Number integer not null,
TimeStampUnixEpoch int, TimeStampUnixEpoch integer not null,
foreign key(MangaID) references Manga(ID) foreign key(MangaID) references Manga(ID)
); );

View File

@@ -15,10 +15,10 @@ type Manga struct {
Title string Title string
TimeStampUnix int64 TimeStampUnix int64
Thumbnail *bytes.Buffer Thumbnail *bytes.Buffer
LastChapterNum int
// Not in DB // Not in DB
LatestChapter *Chapter LatestChapter *Chapter
LastChapterNum int
} }
type Chapter struct { type Chapter struct {
@@ -125,12 +125,12 @@ func (dbMgr *Manager) Save() error {
if count == 0 { if count == 0 {
if m.Thumbnail != nil { if m.Thumbnail != nil {
_, err := db.Exec("INSERT INTO Manga(ID, Title, TimeStampUnixEpoch, Thumbnail) values(?, ?, ?, ?)", m.Id, m.Title, m.TimeStampUnix, m.Thumbnail.Bytes()) _, err := db.Exec("INSERT INTO Manga(ID, Title, TimeStampUnixEpoch, Thumbnail, LatestAvailableChapter) values(?, ?, ?, ?, ?)", m.Id, m.Title, m.TimeStampUnix, m.Thumbnail.Bytes(), m.LastChapterNum)
if err != nil { if err != nil {
return err return err
} }
} else { } else {
_, err := db.Exec("INSERT INTO Manga(ID, Title, TimeStampUnixEpoch ) values(?, ?, ?)", m.Id, m.Title, m.TimeStampUnix) _, err := db.Exec("INSERT INTO Manga(ID, Title, TimeStampUnixEpoch, LatestAvailableChapter) values(?, ?, ?, ?)", m.Id, m.Title, m.TimeStampUnix, m.LastChapterNum)
if err != nil { if err != nil {
return err return err
} }
@@ -143,12 +143,12 @@ func (dbMgr *Manager) Save() error {
} }
if tSet != 0 { if tSet != 0 {
_, err = db.Exec("UPDATE Manga set Title = ?, TimeStampUnixEpoch = ? WHERE ID = ?", m.Title, m.TimeStampUnix, m.Id) _, err = db.Exec("UPDATE Manga set Title = ?, TimeStampUnixEpoch = ?, LatestAvailableChapter = ? WHERE ID = ?", m.Title, m.TimeStampUnix, m.LastChapterNum, m.Id)
if err != nil { if err != nil {
return err return err
} }
} else { } else {
_, err = db.Exec("UPDATE Manga set Title = ?, TimeStampUnixEpoch = ?, Thumbnail = ? WHERE ID = ?", m.Title, m.TimeStampUnix, m.Thumbnail.Bytes(), m.Id) _, err = db.Exec("UPDATE Manga set Title = ?, TimeStampUnixEpoch = ?, Thumbnail = ?, LatestAvailableChapter = ? WHERE ID = ?", m.Title, m.TimeStampUnix, m.Thumbnail.Bytes(), m.LastChapterNum, m.Id)
if err != nil { if err != nil {
return err return err
} }
@@ -197,7 +197,7 @@ func (dbMgr *Manager) load() error {
dbMgr.Rw.Unlock() dbMgr.Rw.Unlock()
}() }()
rows, err := db.Query("SELECT * FROM Manga") rows, err := db.Query("SELECT Id, Title, TimeStampUnixEpoch, Thumbnail, LatestAvailableChapter FROM Manga")
if err != nil { if err != nil {
return err return err
} }
@@ -205,7 +205,7 @@ func (dbMgr *Manager) load() error {
for rows.Next() { for rows.Next() {
manga := Manga{} manga := Manga{}
var thumbnail []byte var thumbnail []byte
if err = rows.Scan(&manga.Id, &manga.Title, &manga.TimeStampUnix, &thumbnail); err != nil { if err = rows.Scan(&manga.Id, &manga.Title, &manga.TimeStampUnix, &thumbnail, &manga.LastChapterNum); err != nil {
return err return err
} }
if len(thumbnail) != 0 { if len(thumbnail) != 0 {
@@ -217,8 +217,9 @@ func (dbMgr *Manager) load() error {
if err = latestChapter.Scan(&chapter.Id, &chapter.Url, &chapter.Name, &chapter.Number, &chapter.TimeStampUnix); err != nil { if err = latestChapter.Scan(&chapter.Id, &chapter.Url, &chapter.Name, &chapter.Number, &chapter.TimeStampUnix); err != nil {
return err return err
} }
dbMgr.Chapters[chapter.Id] = &chapter chapter.Manga = &manga
manga.LatestChapter = &chapter manga.LatestChapter = &chapter
dbMgr.Chapters[chapter.Id] = &chapter
dbMgr.Mangas[manga.Id] = &manga dbMgr.Mangas[manga.Id] = &manga
} }
return nil return nil

View File

@@ -33,7 +33,7 @@ func (s *Server) HandleNew(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "/current/", http.StatusTemporaryRedirect) http.Redirect(w, r, "/current/", http.StatusTemporaryRedirect)
} }
func (s *Server) HandleMenu(w http.ResponseWriter, _ *http.Request) { func (s *Server) HandleMenu(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(view.GetViewTemplate(view.Menu)) tmpl := template.Must(view.GetViewTemplate(view.Menu))
fmt.Println("Locking Rw in handler.go:43") fmt.Println("Locking Rw in handler.go:43")
@@ -75,25 +75,10 @@ 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 == 0 { if manga.LastChapterNum == 0 {
l, err := s.Provider.GetChapterList("/title/" + strconv.Itoa(manga.Id)) err := s.UpdateLatestAvailableChapter(manga)
if err != nil { if err != nil {
continue fmt.Println(err)
} }
le := len(l)
_, c, err := s.Provider.GetTitleAndChapter(l[le-1])
if err != nil {
continue
}
chapterNumberStr := strings.Replace(c, "ch_", "", 1)
i, err := strconv.Atoi(chapterNumberStr)
if err != nil {
continue
}
manga.LastChapterNum = i
} }
t2 = time.Now().UnixNano() t2 = time.Now().UnixNano()
@@ -121,9 +106,29 @@ func (s *Server) HandleMenu(w http.ResponseWriter, _ *http.Request) {
n = time.Now().UnixNano() n = time.Now().UnixNano()
sort := r.URL.Query().Get("sort")
if sort == "" || 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" {
slices.SortStableFunc(mangaViewModels, func(a, b view.MangaViewModel) int {
return cmp.Compare(b.Number, a.Number)
})
} else if sort == "last" {
slices.SortStableFunc(mangaViewModels, func(a, b view.MangaViewModel) int {
aT, err := time.Parse("15:04 (02-01-06)", a.LastTime)
if err != nil {
return cmp.Compare(a.Title, b.Title)
}
bT, err := time.Parse("15:04 (02-01-06)", b.LastTime)
if err != nil {
return cmp.Compare(a.Title, b.Title)
}
return bT.Compare(aT)
})
}
nex = time.Now().UnixNano() nex = time.Now().UnixNano()
fmt.Printf("Sorting took %d ms\n", (nex-n)/1000000) fmt.Printf("Sorting took %d ms\n", (nex-n)/1000000)

View File

@@ -13,6 +13,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"time"
) )
type Server struct { type Server struct {
@@ -46,6 +47,40 @@ func New(provider provider.Provider, db *database.Manager) *Server {
return &s return &s
} }
func (s *Server) Start() error {
http.HandleFunc("/", s.HandleMenu)
http.HandleFunc("/new/", s.HandleNewQuery)
http.HandleFunc("/new/title/{title}/{chapter}", s.HandleNew)
http.HandleFunc("/current/", s.HandleCurrent)
http.HandleFunc("/img/{url}/", s.HandleImage)
http.HandleFunc("POST /next", s.HandleNext)
http.HandleFunc("POST /prev", s.HandlePrev)
http.HandleFunc("POST /exit", s.HandleExit)
http.HandleFunc("POST /delete", s.HandleDelete)
http.HandleFunc("/favicon.ico", s.HandleFavicon)
// Update Latest Chapter every 5 Minutes
go func(s *Server) {
for {
select {
case <-time.After(time.Minute * 5):
s.DbMgr.Rw.Lock()
for _, m := range s.DbMgr.Mangas {
err := s.UpdateLatestAvailableChapter(m)
if err != nil {
fmt.Println(err)
}
}
s.DbMgr.Rw.Unlock()
}
}
}(s)
fmt.Println("Server starting...")
err := http.ListenAndServe(":8000", nil)
return err
}
func (s *Server) LoadNext() { func (s *Server) LoadNext() {
c, err := s.Provider.GetHtml(s.CurrSubUrl) c, err := s.Provider.GetHtml(s.CurrSubUrl)
if err != nil { if err != nil {
@@ -157,6 +192,31 @@ func (s *Server) LoadCurr() {
fmt.Println("Loaded current") fmt.Println("Loaded current")
} }
func (s *Server) UpdateLatestAvailableChapter(manga *database.Manga) error {
fmt.Printf("Updating Manga: %s\n", manga.Title)
l, err := s.Provider.GetChapterList("/title/" + strconv.Itoa(manga.Id))
if err != nil {
return err
}
le := len(l)
_, c, err := s.Provider.GetTitleAndChapter(l[le-1])
if err != nil {
return err
}
chapterNumberStr := strings.Replace(c, "ch_", "", 1)
i, err := strconv.Atoi(chapterNumberStr)
if err != nil {
return err
}
manga.LastChapterNum = i
return nil
}
func (s *Server) LoadThumbnail(manga *database.Manga) (path string, err error) { func (s *Server) LoadThumbnail(manga *database.Manga) (path string, err error) {
strId := strconv.Itoa(manga.Id) strId := strconv.Itoa(manga.Id)

View File

@@ -124,9 +124,9 @@
<table class="table"> <table class="table">
<tr> <tr>
<th>Thumbnail</th> <th>Thumbnail</th>
<th class="table-left">Title</th> <th class="table-left"><a href="?sort=title">Title</a></th>
<th>Current Chapter</th> <th><a href="?sort=chapter">Current Chapter</a></th>
<th>Last Accessed</th> <th><a href="?sort=last">Last Accessed</a></th>
<th>Link</th> <th>Link</th>
<th>Delete</th> <th>Delete</th>
</tr> </tr>