1 Commits

11 changed files with 234 additions and 115 deletions

View File

@@ -3,56 +3,55 @@ package main
import (
"fmt"
"mangaGetter/internal/database"
"mangaGetter/internal/provider"
"mangaGetter/internal/server"
"net/http"
"os"
"os/exec"
"os/signal"
"path/filepath"
"runtime"
"time"
)
func main() {
dir, err := os.UserCacheDir()
if err != nil {
fmt.Println(nil)
return
}
//dir, err := os.UserCacheDir()
//if err != nil {
// fmt.Println(nil)
// return
//}
dirPath := filepath.Join(dir, "MangaGetter")
filePath := filepath.Join(dirPath, "db.sqlite")
//
//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
// }
//}
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
}
}
db := database.NewDatabase(filePath, true)
err = db.Open()
db := database.NewDatabase("db.sqlite", true)
err := db.Open()
if err != nil {
fmt.Println(err)
return
}
s := server.New(&provider.Bato{}, &db)
s := server.New(&db)
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
@@ -64,8 +63,7 @@ func main() {
}()
http.HandleFunc("/", s.HandleMenu)
http.HandleFunc("/new/", s.HandleNewQuery)
http.HandleFunc("/new/title/{title}/{chapter}", s.HandleNew)
http.HandleFunc("POST /new/", s.HandleNewQuery)
http.HandleFunc("/current/", s.HandleCurrent)
http.HandleFunc("/img/{url}/", s.HandleImage)
http.HandleFunc("POST /next", s.HandleNext)

2
go.mod
View File

@@ -6,3 +6,5 @@ require (
github.com/mattn/go-sqlite3 v1.14.22
golang.org/x/text v0.14.0
)
require github.com/google/uuid v1.6.0 // indirect

2
go.sum
View File

@@ -1,3 +1,5 @@
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
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=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=

View File

@@ -0,0 +1,11 @@
package database
type Chapter struct {
Id int
Manga *Manga
InternalIdentifier string
Url string
Name string
Number int
TimeStampUnix int64
}

View File

@@ -1,16 +1,27 @@
create table if not exists Manga (
ID integer not null primary key,
drop table if exists Chapter;
drop table if exists Manga;
create table if not exists Manga
(
ID integer not null primary key autoincrement,
Provider integer not null,
Rating integer,
Title text,
TimeStampUnixEpoch int,
TimeStampUnixEpoch integer,
Thumbnail blob
);
create table if not exists Chapter (
ID integer not null primary key,
create table if not exists Chapter
(
ID integer not null primary key autoincrement,
MangaID integer not null,
InternalIdentifier text not null,
Url text not null,
Name text null,
Number int not null,
TimeStampUnixEpoch int,
foreign key(MangaID) references Manga(ID)
Number integer not null,
TimeStampUnixEpoch integer,
foreign key (MangaID) references Manga (ID)
);

View File

@@ -5,30 +5,12 @@ import (
"database/sql"
_ "embed"
"fmt"
"mangaGetter/internal/provider"
"sync"
_ "github.com/mattn/go-sqlite3"
)
type Manga struct {
Id int
Title string
TimeStampUnix int64
Thumbnail *bytes.Buffer
// Not in DB
LatestChapter *Chapter
}
type Chapter struct {
Id int
Manga *Manga
Url string
Name string
Number int
TimeStampUnix int64
}
type Manager struct {
ConnectionString string
db *sql.DB
@@ -183,7 +165,7 @@ func (dbMgr *Manager) load() error {
dbMgr.Rw.Unlock()
}()
rows, err := db.Query("SELECT * FROM Manga")
rows, err := db.Query("SELECT ID, Provider, Title, TimeStampUnixEpoch, Thumbnail, Rating FROM Manga")
if err != nil {
return err
}
@@ -191,14 +173,16 @@ 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 {
var providerId int
if err = rows.Scan(&manga.Id, &providerId, &manga.Title, &manga.TimeStampUnix, &thumbnail, &manga.Rating); err != nil {
return err
}
manga.Thumbnail = bytes.NewBuffer(thumbnail)
manga.Provider = provider.GetProviderByType(provider.ProviderType(providerId))
dbMgr.Mangas[manga.Id] = &manga
}
rows, err = db.Query("SELECT * FROM Chapter")
rows, err = db.Query("SELECT ID, MangaID, Url, Name, Number, TimeStampUnixEpoch, InternalIdentifier FROM Chapter")
if err != nil {
return err
}
@@ -206,7 +190,7 @@ func (dbMgr *Manager) load() error {
for rows.Next() {
chapter := Chapter{}
var mangaID int
if err = rows.Scan(&chapter.Id, &mangaID, &chapter.Url, &chapter.Name, &chapter.Number, &chapter.TimeStampUnix); err != nil {
if err = rows.Scan(&chapter.Id, &mangaID, &chapter.Url, &chapter.Name, &chapter.Number, &chapter.TimeStampUnix, &chapter.InternalIdentifier); err != nil {
return err
}

View File

@@ -0,0 +1,18 @@
package database
import (
"bytes"
"mangaGetter/internal/provider"
)
type Manga struct {
Id int
Provider provider.Provider
Rating int
Title string
TimeStampUnix int64
Thumbnail *bytes.Buffer
// Not in DB
LatestChapter *Chapter
}

View File

@@ -0,0 +1,100 @@
package provider
import (
"errors"
"fmt"
"io"
"net/http"
"regexp"
"strconv"
)
type Asura struct{}
func (a Asura) GetImageList(html string) (imageUrls []string, err error) {
reg, err := regexp.Compile(`<img decoding="async" class="ts-main-image " src="(.*?)"`)
if err != nil {
return nil, err
}
m := reg.FindAllStringSubmatch(html, -1)
l := len(m)
result := make([]string, l)
for i, match := range m {
result[i] = match[1]
}
return result, nil
}
func (a Asura) GetHtml(url string) (html string, err error) {
resp, err := http.Get(url)
// TODO: Testing for above 300 is dirty
if err != nil && resp.StatusCode > 300 {
return "", errors.New("could not get html")
}
defer func(Body io.ReadCloser) {
err := Body.Close()
if err != nil {
fmt.Printf("Could not close body because: %v\n", err)
}
}(resp.Body)
all, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
h := string(all)
return h, nil
}
func (a Asura) GetNext(html string) (url string, err error) {
//TODO implement me
return "#/next/", nil
}
func (a Asura) GetPrev(html string) (url string, err error) {
//TODO implement me
return "#/prev/", nil
}
func (a Asura) GetTitleAndChapter(url string) (title string, chapter string, err error) {
//TODO implement me
reg, err := regexp.Compile(`\d*-(.*?)-(\d*)/`)
if err != nil {
return "", "", err
}
matches := reg.FindAllStringSubmatch(url, -1)
if len(matches) <= 0 {
return "", "", errors.New("no title or chapter found")
}
return matches[0][1], matches[0][2], nil
}
func (a Asura) GetTitleIdAndChapterId(url string) (titleId int, chapterId int, err error) {
//TODO implement me
reg, err := regexp.Compile(`(\d*)-.*?-(\d*)/`)
if err != nil {
return 0, 0, err
}
matches := reg.FindAllStringSubmatch(url, -1)
if len(matches) <= 0 {
return 0, 0, errors.New("no title or chapter found")
}
t, err := strconv.Atoi(matches[0][1])
if err != nil {
return 0, 0, err
}
c, err := strconv.Atoi(matches[0][2])
return t, c, nil
}
func (a Asura) GetThumbnail(mangaId string) (thumbnailUrl string, err error) {
//TODO implement me
panic("implement me")
}

View File

@@ -0,0 +1,18 @@
package provider
type ProviderType int
const (
BatoId ProviderType = iota
AsuraId ProviderType = iota
)
func GetProviderByType(typeId ProviderType) Provider {
switch typeId {
case BatoId:
return &Bato{}
case AsuraId:
return &Asura{}
}
return nil
}

View File

@@ -17,26 +17,6 @@ import (
"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))
@@ -277,8 +257,6 @@ func (s *Server) HandlePrev(w http.ResponseWriter, r *http.Request) {
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()

View File

@@ -4,18 +4,18 @@ import (
"bytes"
_ "embed"
"fmt"
"github.com/google/uuid"
"io"
"mangaGetter/internal/database"
"mangaGetter/internal/provider"
"mangaGetter/internal/view"
"net/http"
"path/filepath"
"strconv"
"strings"
"sync"
)
type Server struct {
ContextManga *database.Manga
PrevViewModel *view.ImageViewModel
CurrViewModel *view.ImageViewModel
NextViewModel *view.ImageViewModel
@@ -27,18 +27,15 @@ type Server struct {
CurrSubUrl string
PrevSubUrl string
Provider provider.Provider
IsFirst bool
IsLast bool
DbMgr *database.Manager
}
func New(provider provider.Provider, db *database.Manager) *Server {
func New(db *database.Manager) *Server {
s := Server{
ImageBuffers: make(map[string]*bytes.Buffer),
Provider: provider,
DbMgr: db,
Mutex: &sync.Mutex{},
}
@@ -47,7 +44,7 @@ func New(provider provider.Provider, db *database.Manager) *Server {
}
func (s *Server) LoadNext() {
c, err := s.Provider.GetHtml(s.CurrSubUrl)
c, err := s.ContextManga.Provider.GetHtml(s.CurrSubUrl)
if err != nil {
fmt.Println(err)
s.NextSubUrl = ""
@@ -55,7 +52,7 @@ func (s *Server) LoadNext() {
return
}
next, err := s.Provider.GetNext(c)
next, err := s.ContextManga.Provider.GetNext(c)
if err != nil {
fmt.Println(err)
s.NextSubUrl = ""
@@ -63,7 +60,7 @@ func (s *Server) LoadNext() {
return
}
html, err := s.Provider.GetHtml(next)
html, err := s.ContextManga.Provider.GetHtml(next)
if err != nil {
fmt.Println(err)
s.NextSubUrl = ""
@@ -79,7 +76,7 @@ func (s *Server) LoadNext() {
return
}
title, chapter, err := s.Provider.GetTitleAndChapter(next)
title, chapter, err := s.ContextManga.Provider.GetTitleAndChapter(next)
if err != nil {
title = "Unknown"
chapter = "ch_?"
@@ -93,21 +90,21 @@ func (s *Server) LoadNext() {
}
func (s *Server) LoadPrev() {
c, err := s.Provider.GetHtml(s.CurrSubUrl)
c, err := s.ContextManga.Provider.GetHtml(s.CurrSubUrl)
if err != nil {
fmt.Println(err)
s.PrevSubUrl = ""
s.PrevViewModel = nil
return
}
prev, err := s.Provider.GetPrev(c)
prev, err := s.ContextManga.Provider.GetPrev(c)
if err != nil {
fmt.Println(err)
s.PrevSubUrl = ""
s.PrevViewModel = nil
return
}
html, err := s.Provider.GetHtml(prev)
html, err := s.ContextManga.Provider.GetHtml(prev)
if err != nil {
fmt.Println(err)
s.PrevSubUrl = ""
@@ -123,7 +120,7 @@ func (s *Server) LoadPrev() {
return
}
title, chapter, err := s.Provider.GetTitleAndChapter(prev)
title, chapter, err := s.ContextManga.Provider.GetTitleAndChapter(prev)
if err != nil {
title = "Unknown"
chapter = "ch_?"
@@ -138,14 +135,14 @@ func (s *Server) LoadPrev() {
}
func (s *Server) LoadCurr() {
html, err := s.Provider.GetHtml(s.CurrSubUrl)
html, err := s.ContextManga.Provider.GetHtml(s.CurrSubUrl)
if err != nil {
panic(err)
}
imagesCurr, err := s.AppendImagesToBuf(html)
title, chapter, err := s.Provider.GetTitleAndChapter(s.CurrSubUrl)
title, chapter, err := s.ContextManga.Provider.GetTitleAndChapter(s.CurrSubUrl)
if err != nil {
title = "Unknown"
chapter = "ch_?"
@@ -166,7 +163,7 @@ func (s *Server) LoadThumbnail(mangaId int) (path string, err error) {
return strId, nil
}
url, err := s.Provider.GetThumbnail(strconv.Itoa(mangaId))
url, err := s.ContextManga.Provider.GetThumbnail(strconv.Itoa(mangaId))
if err != nil {
return "", err
}
@@ -179,7 +176,7 @@ func (s *Server) LoadThumbnail(mangaId int) (path string, err error) {
}
func (s *Server) AppendImagesToBuf(html string) ([]view.Image, error) {
imgList, err := s.Provider.GetImageList(html)
imgList, err := s.ContextManga.Provider.GetImageList(html)
if err != nil {
return nil, err
}
@@ -194,11 +191,11 @@ func (s *Server) AppendImagesToBuf(html string) ([]view.Image, error) {
if err != nil {
panic(err)
}
name := filepath.Base(url)
g := uuid.New()
s.Mutex.Lock()
s.ImageBuffers[name] = buf
s.ImageBuffers[g.String()] = buf
s.Mutex.Unlock()
images[i] = view.Image{Path: name, Index: i}
images[i] = view.Image{Path: g.String(), Index: i}
wg.Done()
}(i, url, &wg)
}