Made Menu look a bit nicer, added function to add new Manga. Extracted Handler functions to handler.go, fixed bug where new Title would crash

This commit is contained in:
Pablu23
2024-02-23 13:14:56 +01:00
parent 9bc483afb3
commit cd26d937aa
5 changed files with 311 additions and 203 deletions

229
internal/server/handler.go Normal file
View File

@@ -0,0 +1,229 @@
package server
import (
"bytes"
"cmp"
"fmt"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"html/template"
"mangaGetter/internal/database"
"mangaGetter/internal/view"
"net/http"
"slices"
"strconv"
"strings"
"time"
)
func (s *Server) HandleNew(w http.ResponseWriter, r *http.Request) {
title := r.PathValue("title")
chapter := r.PathValue("chapter")
url := fmt.Sprintf("/title/%s/%s", title, chapter)
s.Mutex.Lock()
s.ImageBuffers = make(map[string]*bytes.Buffer)
s.Mutex.Unlock()
s.CurrSubUrl = url
s.PrevSubUrl = ""
s.NextSubUrl = ""
s.LoadCurr()
go s.LoadNext()
go s.LoadPrev()
http.Redirect(w, r, "/current/", http.StatusTemporaryRedirect)
}
func (s *Server) HandleMenu(w http.ResponseWriter, _ *http.Request) {
tmpl := template.Must(view.GetViewTemplate(view.Menu))
s.DbMgr.Rw.Lock()
defer s.DbMgr.Rw.Unlock()
all := s.DbMgr.Mangas
l := len(all)
mangaViewModels := make([]view.MangaViewModel, l)
counter := 0
for _, manga := range all {
title := cases.Title(language.English, cases.Compact).String(strings.Replace(manga.Title, "-", " ", -1))
mangaViewModels[counter] = view.MangaViewModel{
Title: title,
Number: manga.LatestChapter.Number,
// 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,
}
counter++
}
slices.SortStableFunc(mangaViewModels, func(a, b view.MangaViewModel) int {
return cmp.Compare(a.Title, b.Title)
})
menuViewModel := view.MenuViewModel{
Mangas: mangaViewModels,
}
err := tmpl.Execute(w, menuViewModel)
if err != nil {
fmt.Println(err)
}
}
func (s *Server) HandleExit(w http.ResponseWriter, r *http.Request) {
err := s.DbMgr.Save()
if err != nil {
fmt.Println(err)
return
}
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
}
func (s *Server) HandleCurrent(w http.ResponseWriter, _ *http.Request) {
tmpl := template.Must(view.GetViewTemplate(view.Viewer))
s.DbMgr.Rw.Lock()
defer s.DbMgr.Rw.Unlock()
mangaId, chapterId, err := s.Provider.GetTitleIdAndChapterId(s.CurrSubUrl)
if err != nil {
fmt.Println(err)
} else {
title, chapter, err := s.Provider.GetTitleAndChapter(s.CurrSubUrl)
if err != nil {
fmt.Println(err)
} else {
var manga *database.Manga
if s.DbMgr.Mangas[mangaId] == nil {
manga = &database.Manga{
Id: mangaId,
Title: title,
TimeStampUnix: time.Now().Unix(),
}
s.DbMgr.Mangas[mangaId] = manga
} else {
manga = s.DbMgr.Mangas[mangaId]
s.DbMgr.Mangas[mangaId].TimeStampUnix = time.Now().Unix()
}
if s.DbMgr.Chapters[chapterId] == nil {
chapterNumberStr := strings.Replace(chapter, "ch_", "", 1)
number, err := strconv.Atoi(chapterNumberStr)
if err != nil {
fmt.Println(err)
number = 0
}
s.DbMgr.Chapters[chapterId] = &database.Chapter{
Id: chapterId,
Manga: manga,
Url: s.CurrSubUrl,
Name: chapter,
Number: number,
TimeStampUnix: time.Now().Unix(),
}
} else {
s.DbMgr.Chapters[chapterId].TimeStampUnix = time.Now().Unix()
}
s.DbMgr.Mangas[mangaId].LatestChapter = s.DbMgr.Chapters[chapterId]
}
}
err = tmpl.Execute(w, s.CurrViewModel)
if err != nil {
fmt.Println(err)
}
}
func (s *Server) HandleImage(w http.ResponseWriter, r *http.Request) {
u := r.PathValue("url")
s.Mutex.Lock()
buf := s.ImageBuffers[u]
if buf == nil {
fmt.Printf("url: %s is nil\n", u)
w.WriteHeader(400)
return
}
w.Header().Set("Content-Type", "image/webp")
_, err := w.Write(buf.Bytes())
if err != nil {
fmt.Println(err)
}
s.Mutex.Unlock()
}
func (s *Server) HandleNext(w http.ResponseWriter, r *http.Request) {
fmt.Println("Received Next")
if s.PrevViewModel != nil {
go func(viewModel view.ImageViewModel, s *Server) {
s.Mutex.Lock()
for _, img := range viewModel.Images {
delete(s.ImageBuffers, img.Path)
}
s.Mutex.Unlock()
fmt.Println("Cleaned out of scope Last")
}(*s.PrevViewModel, s)
}
s.PrevViewModel = s.CurrViewModel
s.CurrViewModel = s.NextViewModel
s.PrevSubUrl = s.CurrSubUrl
s.CurrSubUrl = s.NextSubUrl
<-s.NextReady
go s.LoadNext()
http.Redirect(w, r, "/current/", http.StatusTemporaryRedirect)
}
func (s *Server) HandlePrev(w http.ResponseWriter, r *http.Request) {
fmt.Println("Received Prev")
if s.NextViewModel != nil {
go func(viewModel view.ImageViewModel, s *Server) {
s.Mutex.Lock()
for _, img := range viewModel.Images {
delete(s.ImageBuffers, img.Path)
}
s.Mutex.Unlock()
fmt.Println("Cleaned out of scope Last")
}(*s.NextViewModel, s)
}
s.NextViewModel = s.CurrViewModel
s.CurrViewModel = s.PrevViewModel
s.NextSubUrl = s.CurrSubUrl
s.CurrSubUrl = s.PrevSubUrl
<-s.PrevReady
go s.LoadPrev()
http.Redirect(w, r, "/current/", http.StatusTemporaryRedirect)
}
func (s *Server) HandleNewQuery(w http.ResponseWriter, r *http.Request) {
sub := r.PostFormValue("subUrl")
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 = ""
s.LoadCurr()
go s.LoadNext()
go s.LoadPrev()
http.Redirect(w, r, "/current/", http.StatusTemporaryRedirect)
}

View File

@@ -3,20 +3,14 @@ package server
import (
"bytes"
"fmt"
"golang.org/x/text/language"
"html/template"
"io"
"mangaGetter/internal/database"
"mangaGetter/internal/provider"
"mangaGetter/internal/view"
"net/http"
"path/filepath"
"strconv"
"strings"
"sync"
"time"
"golang.org/x/text/cases"
)
type Server struct {
@@ -44,50 +38,6 @@ type Server struct {
PrevReady chan bool
}
func (s *Server) HandleImage(w http.ResponseWriter, r *http.Request) {
u := r.PathValue("url")
s.Mutex.Lock()
buf := s.ImageBuffers[u]
if buf == nil {
fmt.Printf("url: %s is nil\n", u)
w.WriteHeader(400)
return
}
w.Header().Set("Content-Type", "image/webp")
_, err := w.Write(buf.Bytes())
if err != nil {
fmt.Println(err)
}
s.Mutex.Unlock()
}
func (s *Server) HandleNext(w http.ResponseWriter, r *http.Request) {
fmt.Println("Received Next")
if s.PrevViewModel != nil {
go func(viewModel view.ImageViewModel, s *Server) {
s.Mutex.Lock()
for _, img := range viewModel.Images {
delete(s.ImageBuffers, img.Path)
}
s.Mutex.Unlock()
fmt.Println("Cleaned out of scope Last")
}(*s.PrevViewModel, s)
}
s.PrevViewModel = s.CurrViewModel
s.CurrViewModel = s.NextViewModel
s.PrevSubUrl = s.CurrSubUrl
s.CurrSubUrl = s.NextSubUrl
<-s.NextReady
go s.LoadNext()
http.Redirect(w, r, "/current/", http.StatusTemporaryRedirect)
}
func (s *Server) LoadNext() {
c, err := s.Provider.GetHtml(s.CurrSubUrl)
if err != nil {
@@ -166,106 +116,6 @@ func (s *Server) LoadPrev() {
s.PrevReady <- true
}
func (s *Server) HandlePrev(w http.ResponseWriter, r *http.Request) {
fmt.Println("Received Prev")
if s.NextViewModel != nil {
go func(viewModel view.ImageViewModel, s *Server) {
s.Mutex.Lock()
for _, img := range viewModel.Images {
delete(s.ImageBuffers, img.Path)
}
s.Mutex.Unlock()
fmt.Println("Cleaned out of scope Last")
}(*s.NextViewModel, s)
}
s.NextViewModel = s.CurrViewModel
s.CurrViewModel = s.PrevViewModel
s.NextSubUrl = s.CurrSubUrl
s.CurrSubUrl = s.PrevSubUrl
<-s.PrevReady
go s.LoadPrev()
http.Redirect(w, r, "/current/", http.StatusTemporaryRedirect)
}
func (s *Server) HandleCurrent(w http.ResponseWriter, _ *http.Request) {
tmpl := template.Must(view.GetViewTemplate(view.Viewer))
s.DbMgr.Rw.Lock()
defer s.DbMgr.Rw.Unlock()
mangaId, chapterId, err := s.Provider.GetTitleIdAndChapterId(s.CurrSubUrl)
if err != nil {
fmt.Println(err)
} else {
title, chapter, err := s.Provider.GetTitleAndChapter(s.CurrSubUrl)
if err != nil {
fmt.Println(err)
} else {
var manga *database.Manga
if s.DbMgr.Mangas[mangaId] == nil {
manga = &database.Manga{
Id: mangaId,
Title: title,
TimeStampUnix: time.Now().Unix(),
}
s.DbMgr.Mangas[mangaId] = manga
} else {
manga = s.DbMgr.Mangas[mangaId]
s.DbMgr.Mangas[mangaId].TimeStampUnix = time.Now().Unix()
}
if s.DbMgr.Chapters[chapterId] == nil {
chapterNumberStr := strings.Replace(chapter, "ch_", "", 1)
number, err := strconv.Atoi(chapterNumberStr)
if err != nil {
fmt.Println(err)
number = 0
}
s.DbMgr.Chapters[chapterId] = &database.Chapter{
Id: chapterId,
Manga: manga,
Url: s.CurrSubUrl,
Name: chapter,
Number: number,
TimeStampUnix: time.Now().Unix(),
}
} else {
s.DbMgr.Chapters[chapterId].TimeStampUnix = time.Now().Unix()
}
}
}
err = tmpl.Execute(w, s.CurrViewModel)
if err != nil {
fmt.Println(err)
}
}
func (s *Server) HandleNew(w http.ResponseWriter, r *http.Request) {
title := r.PathValue("title")
chapter := r.PathValue("chapter")
url := fmt.Sprintf("/title/%s/%s", title, chapter)
s.Mutex.Lock()
s.ImageBuffers = make(map[string]*bytes.Buffer)
s.Mutex.Unlock()
s.CurrSubUrl = url
s.PrevSubUrl = ""
s.NextSubUrl = ""
s.LoadCurr()
go s.LoadNext()
go s.LoadPrev()
http.Redirect(w, r, "/current/", http.StatusTemporaryRedirect)
}
func (s *Server) LoadCurr() {
html, err := s.Provider.GetHtml(s.CurrSubUrl)
if err != nil {
@@ -315,50 +165,6 @@ func (s *Server) AppendImagesToBuf(html string) ([]view.Image, error) {
return images, nil
}
func (s *Server) HandleMenu(w http.ResponseWriter, _ *http.Request) {
tmpl := template.Must(view.GetViewTemplate(view.Menu))
s.DbMgr.Rw.Lock()
defer s.DbMgr.Rw.Unlock()
all := s.DbMgr.Mangas
l := len(all)
mangaViewModels := make([]view.MangaViewModel, l)
counter := 0
for _, manga := range all {
title := cases.Title(language.English, cases.Compact).String(strings.Replace(manga.Title, "-", " ", -1))
mangaViewModels[counter] = view.MangaViewModel{
Title: title,
Number: manga.LatestChapter.Number,
// 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,
}
counter++
}
menuViewModel := view.MenuViewModel{
Mangas: mangaViewModels,
}
err := tmpl.Execute(w, menuViewModel)
if err != nil {
fmt.Println(err)
}
}
func (s *Server) HandleExit(w http.ResponseWriter, r *http.Request) {
err := s.DbMgr.Save()
if err != nil {
fmt.Println(err)
return
}
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
}
func addFileToRam(url string) (*bytes.Buffer, error) {
// Get the data
resp, err := http.Get(url)

View File

@@ -3,19 +3,80 @@
<head>
<meta charset="UTF-8">
<title>Main Menu</title>
<style>
.button-36 {
background-image: linear-gradient(92.88deg, #455EB5 9.16%, #5643CC 43.89%, #673FD7 64.72%);
border-radius: 8px;
border-style: none;
box-sizing: border-box;
color: #FFFFFF;
cursor: pointer;
flex-shrink: 0;
font-family: "Inter UI","SF Pro Display",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,"Open Sans","Helvetica Neue",sans-serif;
font-size: 16px;
font-weight: 500;
height: 4rem;
padding: 0 1.6rem;
text-align: center;
text-shadow: rgba(0, 0, 0, 0.25) 0 3px 8px;
transition: all .5s;
user-select: none;
-webkit-user-select: none;
touch-action: manipulation;
}
.button-36:hover {
box-shadow: rgba(80, 63, 205, 0.5) 0 1px 30px;
transition-duration: .1s;
}
@media (min-width: 768px) {
.button-36 {
padding: 0 2.6rem;
}
}
.table-left{
text-align: left;
}
.table {
width: 100%;
}
td{
text-align: center;
}
</style>
</head>
<body>
<form method="post" action="/new/">
{{/* <label>New Sub Url</label>*/}}
<label>
New Sub Url
<input type="text" name="subUrl">
</label>
<input type="submit" class="button-36">
</form>
{{range .Mangas}}
<div>
<text>Title: {{.Title}}</text>
<text>Current Chapter: {{.Number}}</text>
<text>Last Accessed: {{.LastTime}}</text>
<a href="/new/{{.Url}}}" class="button">Go to last Chapter</a>
</div>
{{end}}
<table class="table">
<tr>
<th class="table-left">Title</th>
<th>Current Chapter</th>
<th>Last Accessed</th>
<th>Link</th>
</tr>
{{range .Mangas}}
<tr>
<td class="table-left">{{.Title}}</td>
<td>{{.Number}}</td>
<td>{{.LastTime}}</td>
<td><a href="/new/{{.Url}}}" class="button-36">Go to last Chapter</a></td>
</tr>
{{end}}
</table>
</body>
</html>