Browse Source

I don't even remember.

This is why you don't write a ton of code, not commit it, then go back to it.
master
Noah Pederson 3 years ago
parent
commit
816904c5ca
12 changed files with 149 additions and 71 deletions
  1. +11
    -4
      .idea/libraries/GOPATH__gocomics_.xml
  2. +10
    -0
      .idea/libraries/Go_SDK.xml
  3. +0
    -13
      .idea/misc.xml
  4. +8
    -8
      config/config.go
  5. +75
    -19
      database/database.go
  6. +2
    -1
      gocomics.go
  7. +3
    -4
      gocomics.iml
  8. +8
    -7
      models/models.go
  9. +9
    -8
      scanner/comicscanner.go
  10. +2
    -3
      utils/utils.go
  11. +1
    -0
      web/api.go
  12. +20
    -4
      web/comicstreamer.go

+ 11
- 4
.idea/libraries/GOPATH__gocomics_.xml View File

@ -1,14 +1,21 @@
<component name="libraryTable">
<library name="GOPATH &lt;gocomics&gt;">
<CLASSES>
<root url="file://$PROJECT_DIR$/../../../github.com" />
<root url="file://$PROJECT_DIR$/../.." />
<root url="file://$PROJECT_DIR$/../../../golang.org" />
<root url="file://$PROJECT_DIR$/../../../9fans.net" />
<root url="file://$PROJECT_DIR$/../.." />
<root url="file://$PROJECT_DIR$/../../../sourcegraph.com" />
<root url="file://$PROJECT_DIR$/../../../gopkg.in" />
<root url="file://$PROJECT_DIR$/../../../github.com" />
</CLASSES>
<JAVADOC />
<SOURCES />
<SOURCES>
<root url="file://$PROJECT_DIR$/../../../golang.org" />
<root url="file://$PROJECT_DIR$/../../../9fans.net" />
<root url="file://$PROJECT_DIR$/../.." />
<root url="file://$PROJECT_DIR$/../../../sourcegraph.com" />
<root url="file://$PROJECT_DIR$/../../../gopkg.in" />
<root url="file://$PROJECT_DIR$/../../../github.com" />
</SOURCES>
<excluded>
<root url="file://$PROJECT_DIR$" />
</excluded>

+ 10
- 0
.idea/libraries/Go_SDK.xml View File

@ -0,0 +1,10 @@
<component name="libraryTable">
<library name="Go SDK">
<CLASSES>
<root url="file://$PROJECT_DIR$/../../../../../Go/src" />
</CLASSES>
<SOURCES>
<root url="file://$PROJECT_DIR$/../../../../../Go/src" />
</SOURCES>
</library>
</component>

+ 0
- 13
.idea/misc.xml View File

@ -7,17 +7,4 @@
</MavenGeneralSettings>
</option>
</component>
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
<OptionsSetting value="true" id="Add" />
<OptionsSetting value="true" id="Remove" />
<OptionsSetting value="true" id="Checkout" />
<OptionsSetting value="true" id="Update" />
<OptionsSetting value="true" id="Status" />
<OptionsSetting value="true" id="Edit" />
<ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_3" default="false" assert-keyword="false" jdk-15="false" project-jdk-name="Go 1.6" project-jdk-type="Go SDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

+ 8
- 8
config/config.go View File

@ -1,20 +1,20 @@
package config
import (
"encoding/json"
"io/ioutil"
"path/filepath"
"log"
"encoding/json"
"path/filepath"
)
type ApiConfig struct {
UseTLS bool `json:"use_tls"`
ForceTLS bool `json:"force_tls"`
SSLPort string `json:"ssl_port"`
HttpPort string `json:"http_port"`
UseTLS bool `json:"use_tls"`
ForceTLS bool `json:"force_tls"`
SSLPort string `json:"ssl_port"`
HttpPort string `json:"http_port"`
ComicFolders []string `json:"comic_folders"`
}
const CONFIG_FILE string = "config.json"
var GlobalConfig ApiConfig
@ -49,4 +49,4 @@ func WriteConfigFile(config *ApiConfig) error {
return err
}
return nil
}
}

+ 75
- 19
database/database.go View File

@ -2,13 +2,12 @@ package database
import (
"database/sql"
"fmt"
"log"
"os"
"strings"
"git.chiefnoah.tech/chiefnoah/gocomics/models"
_ "github.com/mattn/go-sqlite3"
sq "github.com/Masterminds/squirrel"
)
//holds a reference to a database connection and a transaction used for large database processes
@ -172,7 +171,7 @@ func (h *Dbhandler) AddCategory(category *models.Category) error {
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)
stmt, err := h.Db.Prepare(INSERT_CATEGORY)
if err != nil {
log.Println("Error preparing statement: ", err)
return err
@ -180,7 +179,7 @@ func (h *Dbhandler) AddCategory(category *models.Category) error {
defer stmt.Close()
_, err = stmt.Exec(category.Name, 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, "/", category.Name)
if err != nil {
log.Println("Error adding category: ", err)
}
@ -237,7 +236,6 @@ func GetChildrenCategories(ID int) *[]models.Category {
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)
@ -273,6 +271,16 @@ func GetChildrenComicsCount(ID int) int {
return count
}
func GetChildrenComicsById(ID int) *[]models.ComicWrapper {
return nil
}
func GetChildrenComicsByFolder(folder string) *[]models.ComicWrapper {
return nil
}
func CleanCategory() error {
//TODO: ONLY IF CATEGORY IS DIRECTORY STRUCTURE: remove rows that have no comics or children categories in them
return nil
@ -290,7 +298,7 @@ func (h *Dbhandler) AddComic(comic *models.ComicInfo, file *models.ComicFile) er
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)
stmt, err := h.Db.Prepare(INSERT_COMIC_FILE_INFO)
defer stmt.Close()
if err != nil {
log.Println(err)
@ -302,7 +310,7 @@ func (h *Dbhandler) AddComic(comic *models.ComicInfo, file *models.ComicFile) er
if strings.Contains(err.Error(), "UNIQUE") {
log.Print("File already in database, updating to latest info...")
sql := `UPDATE ComicFile SET RelativePath = ?, AbsolutePath = ?, FileName = ? WHERE Hash = ?`
st, err := h.Transaction.Prepare(sql)
st, err := h.Db.Prepare(sql)
defer st.Close()
if err != nil {
log.Println("Unable to prepare statement: ", err)
@ -321,7 +329,7 @@ func (h *Dbhandler) AddComic(comic *models.ComicInfo, file *models.ComicFile) er
}
}
stmt2, err := h.Transaction.Prepare(INSERT_COMIC_INFO)
stmt2, err := h.Db.Prepare(INSERT_COMIC_INFO)
defer stmt2.Close()
if err != nil {
log.Println(err)
@ -344,8 +352,44 @@ func (h *Dbhandler) AddComic(comic *models.ComicInfo, file *models.ComicFile) er
return nil
}
func (h *Dbhandler) GetComics(query *models.ComicWrapper) *[]models.ComicWrapper {
sql := sq.Select("Comic.ID, Title, Series, IssueNumber, PageCount, Hash, Volume, DateAdded, PublishDate, Synopsis, Rating, Status, RelativePath, AbsolutePath, FileName, Filesize").From("Comic").Join("ComicFile USING (Hash)")
if query.ComicInfo.ID > 0 {
sql = sql.Where("Comic.ID = ?", query.ComicInfo.ID)
}
if query.ComicInfo.Hash != "" {
sql = sql.Where("Comic.Hash = ?", query.ComicInfo.Hash)
}
if query.ComicInfo.Title != "" {
sql = sql.Where("Title = ?", query.ComicInfo.Title)
}
if query.ComicInfo.Series != "" {
sql = sql.Where("Series = ?", query.ComicInfo.Title)
}
if query.ComicInfo.IssueNumber > 0 {
sql = sql.Where("IssueNumber = ?", query.ComicInfo.IssueNumber)
}
//TODO: Continue with these query operators
return nil
}
func GetDBHandler() *Dbhandler {
var handler Dbhandler
db, err := sql.Open("sqlite3", "./library.mdb")
if err != nil {
log.Fatal("Unable to open database: ", err)
}
handler.Db = db
handler.Transaction = nil
return &handler
}
func (h *Dbhandler) ExecuteSql(sql string, params ...interface{}) error {
stmt, err := h.Transaction.Prepare(sql)
stmt, err := h.Db.Prepare(sql)
if err != nil {
log.Println("Unable to begin statement in transaction: ", err)
return err
@ -355,22 +399,34 @@ func (h *Dbhandler) ExecuteSql(sql string, params ...interface{}) error {
}
//Creates a new dbhandler object for running a transaction
func BeginTransaction() *Dbhandler {
var handler Dbhandler
func (h *Dbhandler) BeginTransaction() {
db, err := sql.Open("sqlite3", "./library.mdb")
if err != nil {
log.Fatal("Unable to open database: ", err)
if h.Db == nil {
db, err := sql.Open("sqlite3", "./library.mdb")
if err != nil {
log.Fatal("Unable to open database: ", err)
}
h.Db = db
}
handler.Db = db
tx, err := db.Begin()
handler.Transaction = tx
return &handler
if h.Transaction != nil {
log.Printf("Transaction already in progress. Not initializing a new one...")
return
}
tx, err := h.Db.Begin()
if err != nil {
log.Printf("Unable to begin transaction: %s", err)
}
h.Transaction = tx
}
func (h *Dbhandler) FinishTransaction() error {
if h.Transaction == nil {
log.Print("Transaction finished before started. Wut?")
return nil
}
err := h.Transaction.Commit()
defer h.Db.Close()
h.Transaction = nil
return err
}

+ 2
- 1
gocomics.go View File

@ -21,7 +21,8 @@ func main() {
database.Init()
c := config.LoadConfigFile()
go comicscanner.Scan(`./comics`)
go comicscanner.Scan(c.ComicFolders[0])
//go comicscanner.Scan(c.ComicFolders[1])
web.Start(c)
}

+ 3
- 4
gocomics.iml View File

@ -1,14 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="GO_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.images" />
<excludeFolder url="file://$MODULE_DIR$/.temp" />
<excludeFolder url="file://$MODULE_DIR$/comics" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="GOPATH &lt;gocomics&gt;" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Go SDK" level="project" />
</component>
</module>

+ 8
- 7
models/models.go View File

@ -32,6 +32,11 @@ type ComicFile struct {
FileSize int64 `json:"filesize"`
}
type ComicWrapper struct {
ComicInfo ComicInfo `json:"comic_info"`
ComicFile ComicFile `json:"comic_file"`
}
type credit struct {
Author string `json:"author"`
Artist string `json:"artist"`
@ -104,10 +109,6 @@ type CSComic struct {
Teams []string `json:"teams"`
}
type CSComicListResult struct {
}
type CSComicResult struct {
Comics []CSComic `json:"comics"`
TotalCount int `json:"total_count"`
@ -115,9 +116,9 @@ type CSComicResult struct {
}
type CSFolderResponse struct {
Current string `json:"current"`
Folders []CSFolder `json:"folders"`
Comics CSComicCountResponse `json:"comics"`
Current string `json:"current"`
Folders []CSFolder `json:"folders"`
Comics CSComicCountResponse `json:"comics"`
}
type CSComicCountResponse struct {

+ 9
- 8
scanner/comicscanner.go View File

@ -19,18 +19,20 @@ import (
var root string
var dbhandler *database.Dbhandler
//TODO: load comic root path strings from config so we can scan all of them
func Scan(f string) error {
root = f
root = f //I don't remember why I do this lol
//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()
dbhandler = database.GetDBHandler()
dbhandler.BeginTransaction()
defer dbhandler.FinishTransaction()
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)
}
defer dbhandler.FinishTransaction()
err = filepath.Walk(f, visit)
if err != nil {
fmt.Printf("walk error: %v\n", err)
@ -72,10 +74,9 @@ func visit(p string, f os.FileInfo, e error) error {
//fmt.Printf("MD5: %s\n", comicfile.Hash)
dbhandler.AddComic(&models.ComicInfo{}, &comicfile)
go generateCoverImage(&comicfile)
go generateCoverImage(comicfile)
} else {
dir := filepath.Base(filepath.Dir(p))
name := filepath.Base(p)
category := models.Category{Name: name, Parent: dir, IsRoot: false}
@ -97,11 +98,11 @@ func setupDirs() {
os.MkdirAll(utils.CACHE_DIR, 0755)
}
func generateCoverImage(comicfile *models.ComicFile) {
func generateCoverImage(comicfile models.ComicFile) {
//TODO: fix this :(
if _, f := os.Stat(filepath.Join(utils.IMAGES_DIR, comicfile.Hash)); os.IsNotExist(f) {
fmt.Println("No cover image found, generating")
err := utils.ExtractCoverImage(comicfile)
err := utils.ExtractCoverImage(&comicfile)
if err != nil {
log.Println("Extraction error: ", err)
}

+ 2
- 3
utils/utils.go View File

@ -81,9 +81,9 @@ func ExtractComic(comicfile *models.ComicFile) error {
}
func ExtractCoverImage(comicfile *models.ComicFile) error {
r, err := zip.OpenReader(comicfile.AbsolutePath)
r, err := zip.OpenReader(filepath.Join(comicfile.AbsolutePath, comicfile.FileName))
if err != nil {
log.Print("Unable to extract cbz\n")
log.Print("Unable to extract cbz ", err)
return err
}
defer func() {
@ -109,7 +109,6 @@ func ExtractCoverImage(comicfile *models.ComicFile) error {
}
dirname := filepath.Join(wd, IMAGES_DIR)
path := filepath.Join(dirname, comicfile.Hash)
fmt.Println("Extracting to: ", path)
//This probably isn't necessary because we're always dealing with .cbz/.zip files
if f.FileInfo().IsDir() {
os.MkdirAll(path, f.Mode())

+ 1
- 0
web/api.go View File

@ -16,6 +16,7 @@ func Start(c *config.ApiConfig) {
router.GET("/", rootHandler)
router.GET("/dbinfo", dbInfoHandler)
router.GET("/version", versionHandler)
router.GET("/comiclist", comicListHandler)
router.GET("/folders/*path", foldersHandler)
router.Run(c.HttpPort)
router.RunTLS(c.SSLPort, "./test.pem", "./test.key")

+ 20
- 4
web/comicstreamer.go View File

@ -1,13 +1,15 @@
package web
import (
"github.com/gin-gonic/gin"
"net/http"
"net/url"
"path/filepath"
"git.chiefnoah.tech/chiefnoah/gocomics/models"
"git.chiefnoah.tech/chiefnoah/gocomics/database"
"strings"
"fmt"
"github.com/gin-gonic/gin"
"log"
)
@ -27,6 +29,10 @@ func versionHandler(c *gin.Context) {
func comicListHandler(c *gin.Context) {
result := models.CSComicResult{}
c.JSON(http.StatusOK, result)
}
func foldersHandler(c *gin.Context) {
@ -43,12 +49,12 @@ func foldersHandler(c *gin.Context) {
}
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,
URL_Path: "/comiclist?folder=" + url.QueryEscape(category.Full),
}
log.Print("URL_PATH: ", childrenComics.URL_Path)
folders := []models.CSFolder{}
for _, v := range *childrenFolders {
@ -56,9 +62,19 @@ func foldersHandler(c *gin.Context) {
continue
}
csfolder := models.CSFolder{}
csfolder.URL_Path = "/folders/" + strings.Replace(v.Full, "\\", "/", -1)
//This is a stupid workaround to url escape all the folders in the category path without losing the
//path separators.
split_path := strings.Split(v.Full, "/")
for i, folder := range split_path {
//We can't just URL escape this because for some reason url.QueryEscape() will only replace
// spaces with a + instead of %20, and there doesn't seem to be a way around it
split_path[i] = strings.Replace(folder, " ", "%20", -1)
}
v.Full = strings.Join(split_path, "/")
csfolder.URL_Path = "/folders/" + v.Full
csfolder.Name = v.Name
folders = append(folders, csfolder)
log.Print("CS Folder URL_Path: ", csfolder.URL_Path)
}
result := models.CSFolderResponse{

Loading…
Cancel
Save