Well this doesnt work yet, and is likely not the correct way, this needs more thought put into it, probably a complete rewrite is advisable because bringing this into a shape where it could have multiple Providers is hard
This commit is contained in:
11
internal/database/chapter.go
Normal file
11
internal/database/chapter.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package database
|
||||
|
||||
type Chapter struct {
|
||||
Id int
|
||||
Manga *Manga
|
||||
InternalIdentifier string
|
||||
Url string
|
||||
Name string
|
||||
Number int
|
||||
TimeStampUnix int64
|
||||
}
|
||||
@@ -1,16 +1,27 @@
|
||||
create table if not exists Manga (
|
||||
ID integer not null primary key,
|
||||
Title text,
|
||||
TimeStampUnixEpoch int,
|
||||
Thumbnail blob
|
||||
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 integer,
|
||||
Thumbnail blob
|
||||
);
|
||||
|
||||
create table if not exists Chapter (
|
||||
ID integer not null primary key,
|
||||
MangaID integer not null,
|
||||
Url text not null,
|
||||
Name text null,
|
||||
Number int not null,
|
||||
TimeStampUnixEpoch int,
|
||||
foreign key(MangaID) references Manga(ID)
|
||||
);
|
||||
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 integer not null,
|
||||
TimeStampUnixEpoch integer,
|
||||
foreign key (MangaID) references Manga (ID)
|
||||
);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
18
internal/database/manga.go
Normal file
18
internal/database/manga.go
Normal 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
|
||||
}
|
||||
100
internal/provider/asuratoon.go
Normal file
100
internal/provider/asuratoon.go
Normal 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")
|
||||
}
|
||||
18
internal/provider/available_providers.go
Normal file
18
internal/provider/available_providers.go
Normal 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
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user