Added saving of LatestAvailableChapter and updating it in goroutine every 5 Minutes, also Added filtering to menu
This commit is contained in:
@@ -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
|
||||
|
||||
# Features that might get added:
|
||||
- Manga / Chapter History
|
||||
- Searchbar
|
||||
- Better looking UI
|
||||
- Main Screen
|
||||
- Genres and Filter
|
||||
- More Providers like Asuratoon
|
||||
- Performance improvements
|
||||
|
||||
# Pretext
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"mangaGetter/internal/database"
|
||||
"mangaGetter/internal/provider"
|
||||
"mangaGetter/internal/server"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"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() {
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
err := open("http://localhost:8000")
|
||||
@@ -53,11 +41,9 @@ func main() {
|
||||
}
|
||||
}()
|
||||
|
||||
fmt.Println("Server starting...")
|
||||
err = http.ListenAndServe(":8000", nil)
|
||||
err = s.Start()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
create table if not exists Manga (
|
||||
ID integer not null primary key,
|
||||
Title text,
|
||||
TimeStampUnixEpoch int,
|
||||
Thumbnail blob
|
||||
TimeStampUnixEpoch integer not null,
|
||||
Thumbnail blob,
|
||||
LatestAvailableChapter integer not null
|
||||
);
|
||||
|
||||
create table if not exists Chapter (
|
||||
@@ -10,7 +11,7 @@ create table if not exists Chapter (
|
||||
MangaID integer not null,
|
||||
Url text not null,
|
||||
Name text null,
|
||||
Number int not null,
|
||||
TimeStampUnixEpoch int,
|
||||
Number integer not null,
|
||||
TimeStampUnixEpoch integer not null,
|
||||
foreign key(MangaID) references Manga(ID)
|
||||
);
|
||||
@@ -11,14 +11,14 @@ import (
|
||||
)
|
||||
|
||||
type Manga struct {
|
||||
Id int
|
||||
Title string
|
||||
TimeStampUnix int64
|
||||
Thumbnail *bytes.Buffer
|
||||
Id int
|
||||
Title string
|
||||
TimeStampUnix int64
|
||||
Thumbnail *bytes.Buffer
|
||||
LastChapterNum int
|
||||
|
||||
// Not in DB
|
||||
LatestChapter *Chapter
|
||||
LastChapterNum int
|
||||
LatestChapter *Chapter
|
||||
}
|
||||
|
||||
type Chapter struct {
|
||||
@@ -125,12 +125,12 @@ func (dbMgr *Manager) Save() error {
|
||||
|
||||
if count == 0 {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
} 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 {
|
||||
return err
|
||||
}
|
||||
@@ -143,12 +143,12 @@ func (dbMgr *Manager) Save() error {
|
||||
}
|
||||
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
} 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 {
|
||||
return err
|
||||
}
|
||||
@@ -197,7 +197,7 @@ func (dbMgr *Manager) load() error {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
@@ -205,7 +205,7 @@ func (dbMgr *Manager) load() error {
|
||||
for rows.Next() {
|
||||
manga := Manga{}
|
||||
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
|
||||
}
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
dbMgr.Chapters[chapter.Id] = &chapter
|
||||
chapter.Manga = &manga
|
||||
manga.LatestChapter = &chapter
|
||||
dbMgr.Chapters[chapter.Id] = &chapter
|
||||
dbMgr.Mangas[manga.Id] = &manga
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -33,7 +33,7 @@ func (s *Server) HandleNew(w http.ResponseWriter, r *http.Request) {
|
||||
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))
|
||||
|
||||
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
|
||||
// TODO: put this into own Method
|
||||
if manga.LastChapterNum == 0 {
|
||||
l, err := s.Provider.GetChapterList("/title/" + strconv.Itoa(manga.Id))
|
||||
err := s.UpdateLatestAvailableChapter(manga)
|
||||
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()
|
||||
@@ -121,9 +106,29 @@ func (s *Server) HandleMenu(w http.ResponseWriter, _ *http.Request) {
|
||||
|
||||
n = time.Now().UnixNano()
|
||||
|
||||
slices.SortStableFunc(mangaViewModels, func(a, b view.MangaViewModel) int {
|
||||
return cmp.Compare(a.Title, b.Title)
|
||||
})
|
||||
sort := r.URL.Query().Get("sort")
|
||||
|
||||
if sort == "" || sort == "title" {
|
||||
slices.SortStableFunc(mangaViewModels, func(a, b view.MangaViewModel) int {
|
||||
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()
|
||||
fmt.Printf("Sorting took %d ms\n", (nex-n)/1000000)
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
@@ -46,6 +47,40 @@ func New(provider provider.Provider, db *database.Manager) *Server {
|
||||
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() {
|
||||
c, err := s.Provider.GetHtml(s.CurrSubUrl)
|
||||
if err != nil {
|
||||
@@ -157,6 +192,31 @@ func (s *Server) LoadCurr() {
|
||||
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) {
|
||||
strId := strconv.Itoa(manga.Id)
|
||||
|
||||
|
||||
@@ -124,9 +124,9 @@
|
||||
<table class="table">
|
||||
<tr>
|
||||
<th>Thumbnail</th>
|
||||
<th class="table-left">Title</th>
|
||||
<th>Current Chapter</th>
|
||||
<th>Last Accessed</th>
|
||||
<th class="table-left"><a href="?sort=title">Title</a></th>
|
||||
<th><a href="?sort=chapter">Current Chapter</a></th>
|
||||
<th><a href="?sort=last">Last Accessed</a></th>
|
||||
<th>Link</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
|
||||
Reference in New Issue
Block a user