From a8ba8728dc91bc174160ee520eb52af18b7300bc Mon Sep 17 00:00:00 2001 From: Pablu23 Date: Fri, 1 Mar 2024 14:31:38 +0100 Subject: [PATCH] Added Last Chapter functionality to see how many more chapters you have, also kinda works as update Status bar changed it to only load latest chapter instead of all chapters for manga Added develop and release db from different locations Added stopwatch for future performance improvement metrics --- cmd/mangaGetter/develop.go | 7 +++ cmd/mangaGetter/main.go | 33 +------------- cmd/mangaGetter/release.go | 38 ++++++++++++++++ internal/database/database.go | 21 ++------- internal/provider/bato.go | 21 +++++++-- internal/provider/provider.go | 1 + internal/server/handler.go | 81 ++++++++++++++++++++++++++++++--- internal/view/Views/menu.gohtml | 2 +- internal/view/viewmodels.go | 1 + 9 files changed, 147 insertions(+), 58 deletions(-) create mode 100644 cmd/mangaGetter/develop.go create mode 100644 cmd/mangaGetter/release.go diff --git a/cmd/mangaGetter/develop.go b/cmd/mangaGetter/develop.go new file mode 100644 index 0000000..eed9a77 --- /dev/null +++ b/cmd/mangaGetter/develop.go @@ -0,0 +1,7 @@ +//go:build Develop + +package main + +func getDbPath() string { + return "db.sqlite" +} diff --git a/cmd/mangaGetter/main.go b/cmd/mangaGetter/main.go index 73a39f3..a4efa3e 100644 --- a/cmd/mangaGetter/main.go +++ b/cmd/mangaGetter/main.go @@ -9,44 +9,15 @@ import ( "os" "os/exec" "os/signal" - "path/filepath" "runtime" "time" ) func main() { - dir, err := os.UserCacheDir() - if err != nil { - fmt.Println(nil) - return - } - - dirPath := filepath.Join(dir, "MangaGetter") - filePath := filepath.Join(dirPath, "db.sqlite") - - if _, err := os.Stat(dirPath); os.IsNotExist(err) { - err = os.Mkdir(dirPath, os.ModePerm) - if err != nil { - fmt.Println(err) - return - } - } - - if _, err := os.Stat(filePath); os.IsNotExist(err) { - f, err := os.Create(filePath) - if err != nil { - fmt.Println(err) - return - } - err = f.Close() - if err != nil { - fmt.Println(err) - return - } - } + filePath := getDbPath() db := database.NewDatabase(filePath, true) - err = db.Open() + err := db.Open() if err != nil { fmt.Println(err) return diff --git a/cmd/mangaGetter/release.go b/cmd/mangaGetter/release.go new file mode 100644 index 0000000..265beae --- /dev/null +++ b/cmd/mangaGetter/release.go @@ -0,0 +1,38 @@ +//go:build !Develop + +package main + +import ( + "os" + "path/filepath" +) + +func getDbPath() string { + dir, err := os.UserCacheDir() + if err != nil { + panic(err) + } + + dirPath := filepath.Join(dir, "MangaGetter") + filePath := filepath.Join(dirPath, "db.sqlite") + + if _, err := os.Stat(dirPath); os.IsNotExist(err) { + err = os.Mkdir(dirPath, os.ModePerm) + if err != nil { + panic(err) + } + } + + if _, err := os.Stat(filePath); os.IsNotExist(err) { + f, err := os.Create(filePath) + if err != nil { + panic(err) + } + err = f.Close() + if err != nil { + panic(err) + } + } + + return filePath +} diff --git a/internal/database/database.go b/internal/database/database.go index f145369..fd40f53 100644 --- a/internal/database/database.go +++ b/internal/database/database.go @@ -195,28 +195,15 @@ func (dbMgr *Manager) load() error { return err } manga.Thumbnail = bytes.NewBuffer(thumbnail) - dbMgr.Mangas[manga.Id] = &manga - } - rows, err = db.Query("SELECT * FROM Chapter") - if err != nil { - return err - } - - for rows.Next() { + latestChapter := db.QueryRow("SELECT Id, Url, Name, Number, TimeStampUnixEpoch FROM Chapter where MangaID = ? ORDER BY TimeStampUnixEpoch desc LIMIT 1", manga.Id) chapter := Chapter{} - var mangaID int - if err = rows.Scan(&chapter.Id, &mangaID, &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 } - - chapter.Manga = dbMgr.Mangas[mangaID] - if dbMgr.Mangas[mangaID].LatestChapter == nil || dbMgr.Mangas[mangaID].LatestChapter.TimeStampUnix < chapter.TimeStampUnix { - dbMgr.Mangas[mangaID].LatestChapter = &chapter - } - dbMgr.Chapters[chapter.Id] = &chapter + manga.LatestChapter = &chapter + dbMgr.Mangas[manga.Id] = &manga } - return nil } diff --git a/internal/provider/bato.go b/internal/provider/bato.go index 4574e98..7fc5db0 100644 --- a/internal/provider/bato.go +++ b/internal/provider/bato.go @@ -109,9 +109,24 @@ func (b *Bato) GetTitleIdAndChapterId(url string) (titleId int, chapterId int, e return t, c, err } -//func (b *Bato) GetChapterList(url string) (chapterIds []int, err error) { -// -//} +func (b *Bato) GetChapterList(subUrl string) (subUrls []string, err error) { + reg, err := regexp.Compile(`
.*?Chapter (\d*)`) + if err != nil { + return nil, err + } + + html, err := b.GetHtml(subUrl) + if err != nil { + return nil, err + } + + subUrls = make([]string, 0) + matches := reg.FindAllStringSubmatch(html, -1) + for _, match := range matches { + subUrls = append(subUrls, match[1]) + } + return subUrls, nil +} func (b *Bato) GetThumbnail(subUrl string) (thumbnailUrl string, err error) { url := fmt.Sprintf("https://bato.to/title/%s", subUrl) diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 7ff98c2..994cebd 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -8,4 +8,5 @@ type Provider interface { GetTitleAndChapter(url string) (title string, chapter string, err error) GetTitleIdAndChapterId(url string) (titleId int, chapterId int, err error) GetThumbnail(mangaId string) (thumbnailUrl string, err error) + GetChapterList(url string) (urls []string, err error) } diff --git a/internal/server/handler.go b/internal/server/handler.go index a79a090..d32b36c 100644 --- a/internal/server/handler.go +++ b/internal/server/handler.go @@ -52,19 +52,56 @@ func (s *Server) HandleMenu(w http.ResponseWriter, _ *http.Request) { mangaViewModels := make([]view.MangaViewModel, l) counter := 0 + n := time.Now().UnixNano() + + var thumbNs int64 = 0 + var titNs int64 = 0 + + //TODO: Change all this to be more performant for _, manga := range all { title := cases.Title(language.English, cases.Compact).String(strings.Replace(manga.Title, "-", " ", -1)) + t1 := time.Now().UnixNano() + thumbnail, err := s.LoadThumbnail(manga.Id) + //TODO: Add default picture instead of not showing Manga at all if err != nil { continue } manga.Thumbnail = s.ImageBuffers[thumbnail] + t2 := time.Now().UnixNano() + + thumbNs += t2 - t1 + + t1 = time.Now().UnixNano() + // This is very slow + l, err := s.Provider.GetChapterList("/title/" + strconv.Itoa(manga.Id)) + if err != nil { + continue + } + + 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 + } + t2 = time.Now().UnixNano() + + titNs += t2 - t1 + mangaViewModels[counter] = view.MangaViewModel{ - ID: manga.Id, - Title: title, - Number: manga.LatestChapter.Number, + ID: manga.Id, + Title: title, + Number: manga.LatestChapter.Number, + LastNumber: i, // I Hate this time Format... 15 = hh, 04 = mm, 02 = DD, 01 = MM, 06 == YY LastTime: time.Unix(manga.TimeStampUnix, 0).Format("15:04 (02-01-06)"), Url: manga.LatestChapter.Url, @@ -73,10 +110,21 @@ func (s *Server) HandleMenu(w http.ResponseWriter, _ *http.Request) { counter++ } + fmt.Printf("Loading Thumbnails took %d ms\n", (thumbNs)/1000000) + fmt.Printf("Loading latest Chapter took %d ms\n", (titNs)/1000000) + + nex := time.Now().UnixNano() + fmt.Printf("Creating Viewmodels took %d ms\n", (nex-n)/1000000) + + n = time.Now().UnixNano() + slices.SortStableFunc(mangaViewModels, func(a, b view.MangaViewModel) int { return cmp.Compare(a.Title, b.Title) }) + nex = time.Now().UnixNano() + fmt.Printf("Sorting took %d ms\n", (nex-n)/1000000) + menuViewModel := view.MenuViewModel{ Mangas: mangaViewModels, } @@ -117,7 +165,31 @@ func (s *Server) HandleExit(w http.ResponseWriter, r *http.Request) { return } + fmt.Println("Cleaned out of scope Last") + http.Redirect(w, r, "/", http.StatusTemporaryRedirect) + + go func() { + s.Mutex.Lock() + if s.PrevViewModel != nil { + for _, img := range s.PrevViewModel.Images { + delete(s.ImageBuffers, img.Path) + } + } + if s.CurrViewModel != nil { + + for _, img := range s.CurrViewModel.Images { + delete(s.ImageBuffers, img.Path) + } + } + if s.NextViewModel != nil { + + for _, img := range s.NextViewModel.Images { + delete(s.ImageBuffers, img.Path) + } + } + s.Mutex.Unlock() + }() } func (s *Server) HandleCurrent(w http.ResponseWriter, _ *http.Request) { @@ -279,9 +351,6 @@ func (s *Server) HandleNewQuery(w http.ResponseWriter, r *http.Request) { url := fmt.Sprintf("/title/%s", sub) - s.Mutex.Lock() - s.ImageBuffers = make(map[string]*bytes.Buffer) - s.Mutex.Unlock() s.CurrSubUrl = url s.PrevSubUrl = "" s.NextSubUrl = "" diff --git a/internal/view/Views/menu.gohtml b/internal/view/Views/menu.gohtml index 8537db9..f93d9e2 100644 --- a/internal/view/Views/menu.gohtml +++ b/internal/view/Views/menu.gohtml @@ -138,7 +138,7 @@ {{.Title}} - {{.Number}} + {{.Number}} / {{.LastNumber}} {{.LastTime}} diff --git a/internal/view/viewmodels.go b/internal/view/viewmodels.go index 06b224d..254fd55 100644 --- a/internal/view/viewmodels.go +++ b/internal/view/viewmodels.go @@ -14,6 +14,7 @@ type MangaViewModel struct { ID int Title string Number int + LastNumber int LastTime string Url string ThumbnailUrl string