Browse Source

Directorying structure almost done. Crashes on certain requests.

master
Noah Pederson 4 years ago
parent
commit
6732b839cb
7 changed files with 225 additions and 28 deletions
  1. +3
    -1
      .gitignore
  2. +48
    -4
      config/config.go
  3. +103
    -11
      database/database.go
  4. +2
    -3
      gocomics.go
  5. +17
    -0
      models/models.go
  6. +6
    -8
      scanner/comicscanner.go
  7. +46
    -1
      web/comicstreamer.go

+ 3
- 1
.gitignore View File

@ -10,6 +10,7 @@ _obj
_test
comics
.images
.temp
# Architecture specific extensions/prefixes
*.[568vq]
@ -30,4 +31,5 @@ _testmain.go
*.mdb
*.key
*.pem
*.txt
*.txt
*.json

+ 48
- 4
config/config.go View File

@ -1,8 +1,52 @@
package config
import (
"io/ioutil"
"path/filepath"
"log"
"encoding/json"
)
type ApiConfig struct {
UseTLS bool
ForceTLS bool
SSLPort string
HttpPort string
UseTLS bool `json:"use_tls"`
ForceTLS bool `json:"force_tls"`
SSLPort string `json:"ssl_port"`
HttpPort string `json:"http_port"`
}
const CONFIG_FILE string = "config.json"
var GlobalConfig ApiConfig
func LoadConfigFile() *ApiConfig {
f, err := ioutil.ReadFile(CONFIG_FILE)
if err != nil {
log.Println("Could not load config: ", err)
//TODO: if the file wasn't found, generate default config
}
config := ApiConfig{}
err = json.Unmarshal(f, &config)
if err != nil {
log.Fatal("Could not load config: ", err)
}
GlobalConfig = config
return &config
}
func WriteConfigFile(config *ApiConfig) error {
p := filepath.Join(".", CONFIG_FILE)
json, err := json.MarshalIndent(*config, "", " ")
if err != nil {
log.Println("Unable to marshal settings to JSON: ", err)
return err
}
err = ioutil.WriteFile(p, json, 0644)
if err != nil {
log.Println("Unable to write config file: ", err)
return err
}
return nil
}

+ 103
- 11
database/database.go View File

@ -86,7 +86,7 @@ func Init() {
'Synopsis' TEXT,
'Rating' REAL DEFAULT 0.0,
'Status' TEXT,
'CategoryID' INTEGER,
'CategoryID' INTEGER DEFAULT 1,
FOREIGN KEY('CategoryID') REFERENCES 'Category'('ID')
FOREIGN KEY('ComicFileID') REFERENCES 'ComicFile'('ID')
);`
@ -169,12 +169,8 @@ func Init() {
}
func (h *Dbhandler) AddCategory(category *models.Category) error {
//I'm guessing the "OR REPLACE" part will cause issues later one when people don't want changing the directory
//structure of their comics to lose their categories. It might not be a problem if categories are purely based on
//the actual directory structure, but if the are arbitrarily set (which I plan on letting you do) it will have to
//rely on the CategoryID field of the Comic table, which won't get updated when a row is replaced because it generates
//a new ID. A possible solution is to use SQL triggers, but I'm unfamiliar with them, I'll have to look into it.
INSERT_CATEGORY := `INSERT OR REPLACE INTO Category(Name, Parent, IsRoot, Full) VALUES(?, (SELECT ID FROM Category WHERE Name = ?), ?, (SELECT Full FROM Category WHERE Name = ?) || ? || ?)`
INSERT_CATEGORY := `INSERT OR REPLACE INTO Category(ID, Name, Parent, IsRoot, Full) VALUES(IFNULL((SELECT ID FROM Category WHERE Name = ?), (SELECT SEQ from sqlite_sequence WHERE name='Category') + 1) ,?, IFNULL((SELECT ID FROM Category WHERE Name = ?), 1), ?, IFNULL((SELECT Full FROM Category WHERE Name = ?), "0") || ? || ?)`
stmt, err := h.Transaction.Prepare(INSERT_CATEGORY)
if err != nil {
@ -184,19 +180,115 @@ func (h *Dbhandler) AddCategory(category *models.Category) error {
defer stmt.Close()
_, err = stmt.Exec(category.Name, category.Parent, category.IsRoot, category.Parent, fmt.Sprintf("%c", os.PathSeparator), category.Name)
_, err = stmt.Exec(category.Name, category.Name, category.Parent, category.IsRoot, category.Parent, fmt.Sprintf("%c", os.PathSeparator), category.Name)
if err != nil {
log.Println("Error adding category: ", err)
}
return err
}
func GetCategory(query *models.Category) *models.Category {
db, err := sql.Open("sqlite3", "./library.mdb")
if err != nil {
log.Fatal("Unable to open database: ", err)
}
defer db.Close()
//var value *models.Category
var row *sql.Row
var value models.Category
sql := `SELECT ID, Name, Parent, IsRoot, Full FROM Category WHERE `
if query.ID > 0 {
sql += `ID = ?`
row = db.QueryRow(sql, query.ID)
} else if query.Name != "" {
sql += `Name = ?`
row = db.QueryRow(sql, query.Name)
} else if query.ParentId > 0 {
sql += `Parent = ?`
row = db.QueryRow(sql, query.ParentId)
} else if query.Full != "" {
sql += `Full LIKE ?`
row = db.QueryRow(sql, query.Full)
} else if query.Parent != "" {
sql += `Full LIKE ?`
row = db.QueryRow(sql, query.Parent)
}
err = row.Scan(&value.ID, &value.Name, &value.ParentId, &value.IsRoot, &value.Full)
if err != nil {
log.Println("Unable to get Category: ", err)
return nil
}
return &value
}
func GetChildrenCategories(ID int) *[]models.Category {
db, err := sql.Open("sqlite3", "./library.mdb")
if err != nil {
log.Fatal("Unable to open database: ", err)
}
defer db.Close()
sql := `SELECT ID, Name, Parent, IsRoot, Full FROM Category WHERE Parent = ?`
rows, err := db.Query(sql, ID)
if err != nil {
log.Println("Unable to get children categories: ", err)
return &[]models.Category{}
}
children := []models.Category{}
for rows.Next() {
category := models.Category{}
rows.Scan(&category.ID, &category.Name, &category.ParentId, &category.IsRoot, &category.Full)
children = append(children, category)
}
return &children
}
func GetChildrenComicsCount(ID int) int {
db, err := sql.Open("sqlite3", "./library.mdb")
if err != nil {
log.Fatal("Unable to open database: ", err)
}
defer db.Close()
sql := `SELECT COUNT(*) FROM Comic WHERE CategoryID = ?`
row := db.QueryRow(sql, ID)
var count int = 0
err = row.Scan(&count)
if err != nil {
log.Println("Couldn't get children comics: ", err)
count = 0
}
return count
}
func CleanCategory() error {
//TODO: ONLY IF CATEGORY IS DIRECTORY STRUCTURE: remove rows that have no comics or children categories in them
return nil
}
func (h *Dbhandler) AddComic(comic *models.ComicInfo, file *models.ComicFile) error {
//The Hash field is shared because I felt like it. It doesn't really need to be shared but it helps to have a
//uniquely identifying field besides the ID generated by the database
INSERT_COMIC_FILE_INFO := `INSERT INTO ComicFile(RelativePath, AbsolutePath, FileName, Hash, Filesize) VALUES(?, ?, ?, ?, ?)`
INSERT_COMIC_INFO := `INSERT INTO Comic(Title, Series, IssueNumber, PageCount, ComicFileID, Hash, Volume, DateAdded, PublishDate, Synopsis, Rating, Status) VALUES (?, ?, ?, ?, (SELECT ID FROM ComicFile WHERE ComicFile.Hash = ?), ?, ?, ?, ?, ?, ?, ?)`
INSERT_COMIC_FILE_INFO := `INSERT INTO ComicFile(RelativePath, AbsolutePath, FileName, Hash, Filesize)
VALUES(?, ?, ?, ?, ?)`
INSERT_COMIC_INFO := `INSERT INTO Comic(Title, Series, IssueNumber, PageCount, ComicFileID, Hash, Volume,
DateAdded, PublishDate, Synopsis, Rating, Status, CategoryID)
VALUES (?, ?, ?, ?, (SELECT ID FROM ComicFile WHERE ComicFile.Hash = ?), ?, ?, ?, ?, ?, ?, ?,
IFNULL((SELECT ID FROM Category WHERE Full = (SELECT '0\' || RelativePath FROM ComicFile WHERE ComicFile.Hash = ?)), 1))`
stmt, err := h.Transaction.Prepare(INSERT_COMIC_FILE_INFO)
defer stmt.Close()
@ -236,7 +328,7 @@ func (h *Dbhandler) AddComic(comic *models.ComicInfo, file *models.ComicFile) er
return err
}
_, err = stmt2.Exec(comic.Title, comic.Series, comic.IssueNumber, comic.PageCount, file.Hash, file.Hash, comic.Volume,
comic.DateAdded, comic.PublishDate, comic.Synopsis, comic.Rating, comic.Status)
comic.DateAdded, comic.PublishDate, comic.Synopsis, comic.Rating, comic.Status, file.Hash)
if err != nil {
if strings.Contains(err.Error(), "UNIQUE") {
//this means the record already exists. We don't want to overwrite tags here so we do nothing

+ 2
- 3
gocomics.go View File

@ -20,9 +20,8 @@ func main() {
//log.SetOutput(f)
database.Init()
config := &config.ApiConfig{
UseTLS: true, ForceTLS: false, SSLPort: ":3008", HttpPort: ":3000"}
c := config.LoadConfigFile()
go comicscanner.Scan(`./comics`)
web.Start(config)
web.Start(c)
}

models/comics.go → models/models.go View File

@ -105,6 +105,7 @@ type CSComic struct {
}
type CSComicListResult struct {
}
type CSComicResult struct {
@ -112,3 +113,19 @@ type CSComicResult struct {
TotalCount int `json:"total_count"`
PageCount int `json:"page_count"`
}
type CSFolderResponse struct {
Current string `json:"current"`
Folders []CSFolder `json:"folders"`
Comics CSComicCountResponse `json:"comics"`
}
type CSComicCountResponse struct {
Count int `json:"count"`
URL_Path string `json:"url_path"`
}
type CSFolder struct {
URL_Path string `json:"url_path"`
Name string `json:"name"`
}

+ 6
- 8
scanner/comicscanner.go View File

@ -21,12 +21,12 @@ var dbhandler *database.Dbhandler
func Scan(f string) error {
root = f
base := filepath.Base(f)
//base := filepath.Base(f)
//models.Category{ID: 1, Name: base, Parent: 1, IsRoot:true, Full: base}
//generates the temp and image directories
setupDirs()
dbhandler = database.BeginTransaction()
err := dbhandler.ExecuteSql(`INSERT OR IGNORE INTO Category(ID, Name, Parent, IsRoot, Full) VALUES(?, ?, ?, ?, ?)`, 1, base, 1, true, base)
err := dbhandler.ExecuteSql(`INSERT OR IGNORE INTO Category(ID, Name, Parent, IsRoot, Full) VALUES(?, ?, ?, ?, ?)`, 1, "0", 1, true, "0")
if err != nil {
log.Println("Error creating start category dir: ", err)
}
@ -75,15 +75,13 @@ func visit(p string, f os.FileInfo, e error) error {
go generateCoverImage(&comicfile)
} else {
//TODO: check if directory, if directory and directory=category is enabled (default), add it as a category
//limitation: category names (ie. directory names) MUST be unique.
if p == root {
//If the current directory is the root directory, we don't want to do anything
return nil
}
dir := filepath.Base(filepath.Dir(p))
name := filepath.Base(p)
category := models.Category{Name: name, Parent: dir, IsRoot: false}
if dir == root {
category.IsRoot = true
}
dbhandler.AddCategory(&category)
}
return nil

+ 46
- 1
web/comicstreamer.go View File

@ -3,6 +3,11 @@ package web
import (
"github.com/gin-gonic/gin"
"net/http"
"path/filepath"
"git.chiefnoah.tech/chiefnoah/gocomics/models"
"git.chiefnoah.tech/chiefnoah/gocomics/database"
"strings"
"fmt"
)
@ -26,6 +31,46 @@ func comicListHandler(c *gin.Context) {
func foldersHandler(c *gin.Context) {
path := c.Param("path")
if path == "/" {
path = "/0"
}
c.String(http.StatusOK, "Test: " + path)
base := filepath.Base(path)
fmt.Println("Base: ", base)
var query = models.Category{
Name: base,
}
category := database.GetCategory(&query)
childrenFolders := database.GetChildrenCategories(category.ID)
fmt.Printf("Children folders: %+v", childrenFolders)
childrenComicsCount := database.GetChildrenComicsCount(category.ID)
childrenComics := models.CSComicCountResponse{
Count: childrenComicsCount,
URL_Path: "/comiclist?folder=" + category.Full,
}
folders := []models.CSFolder{}
for _, v := range *childrenFolders {
if(v.ID == 1) {
continue
}
csfolder := models.CSFolder{}
csfolder.URL_Path = "/folders/" + strings.Replace(v.Full, "\\", "/", -1)
csfolder.Name = v.Name
folders = append(folders, csfolder)
}
result := models.CSFolderResponse{
Current: category.Full,
Folders: folders,
Comics: childrenComics,
}
//for _, v := range categoryNames {
//TODO: query database for category
//}
c.JSON(http.StatusOK, result)
}

Loading…
Cancel
Save