diff --git a/documentTypes.plist b/documentTypes.plist
index babe49f..e4e7ba6 100644
--- a/documentTypes.plist
+++ b/documentTypes.plist
@@ -197,4 +197,60 @@
LSTypeIsPackage
+
+ CFBundleTypeExtensions
+
+ cbz
+ CBZ
+
+ CFBundleTypeIconFile
+ cbz.icns
+ CFBundleTypeMIMETypes
+
+ application/vnd.comicbook+zip
+ application/x-cbz
+
+ CFBundleTypeName
+ Comic Book Zip Archive
+ CFBundleTypeOSTypes
+
+ CBZ
+
+ CFBundleTypeRole
+ Viewer
+ LSItemContentTypes
+
+ in.yetaga.why.cbz
+
+ LSTypeIsPackage
+
+
+
+ CFBundleTypeExtensions
+
+ cbr
+ CBR
+
+ CFBundleTypeIconFile
+ cbr.icns
+ CFBundleTypeMIMETypes
+
+ application/vnd.comicbook-rar
+ application/x-cbr
+
+ CFBundleTypeName
+ Comic Book Rar Archive
+ CFBundleTypeOSTypes
+
+ CBR
+
+ CFBundleTypeRole
+ Viewer
+ LSItemContentTypes
+
+ in.yetaga.why.cbr
+
+ LSTypeIsPackage
+
+
\ No newline at end of file
diff --git a/filetypes/filetypes.go b/filetypes/filetypes.go
index 96eb4dd..98ccf8f 100644
--- a/filetypes/filetypes.go
+++ b/filetypes/filetypes.go
@@ -84,6 +84,24 @@ var Valid = []FileDescription{
OSTypes: []string{"WEBP"},
ItemContentTypes: "org.webmproject.webp",
},
+ {
+ TkTypeName: "CBZ",
+ MacExtensions: []string{"cbz", "CBZ"},
+ IconFile: "cbz.icns",
+ MIMETypes: []string{"application/vnd.comicbook+zip", "application/x-cbz"},
+ TypeName: "Comic Book Zip Archive",
+ OSTypes: []string{"CBZ"},
+ ItemContentTypes: "in.yetaga.why.cbz",
+ },
+ {
+ TkTypeName: "CBR",
+ MacExtensions: []string{"cbr", "CBR"},
+ IconFile: "cbr.icns",
+ MIMETypes: []string{"application/vnd.comicbook-rar", "application/x-cbr"},
+ TypeName: "Comic Book Rar Archive",
+ OSTypes: []string{"CBR"},
+ ItemContentTypes: "in.yetaga.why.cbr",
+ },
}
func GetTkTypes(fds []FileDescription) []tk.FileType {
diff --git a/main.go b/main.go
index f4fb674..d2da182 100644
--- a/main.go
+++ b/main.go
@@ -1,9 +1,11 @@
package main
import (
+ "archive/zip"
_ "embed"
"fmt"
"image"
+ "io"
"log"
"os"
"path/filepath"
@@ -22,7 +24,12 @@ import (
type state struct {
dir string
i int
- images []string
+ images []imagefile
+}
+
+type imagefile struct {
+ contents *image.Image
+ filename string
}
//go:embed media/noise.png
@@ -41,7 +48,20 @@ var fileListBindVar = tk.Variable("FileList")
var directoryState state
func (d state) pathToImageAtIndex(i int) string {
- return filepath.Join(directoryState.dir, directoryState.images[i])
+ return filepath.Join(directoryState.dir, directoryState.images[i].filename)
+}
+
+func (d state) imageWithFilename(s string) (imagefile, int, error) {
+ for i, f := range directoryState.images {
+ if f.filename == s {
+ return directoryState.images[i], i, nil
+ }
+ }
+ return imagefile{}, 0, fmt.Errorf("not found")
+}
+
+func (d state) setImage(i int, img *image.Image) {
+ d.images[i].contents = img
}
func must[T any](t T, err error) T {
@@ -62,7 +82,49 @@ func newFileInDirectory() {
return
}
// GetOpenFile returns an array split on spaces!
- newBrowse(strings.Join(files, " "))
+ file := strings.Join(files, " ")
+ if filepath.Ext(file) == ".cbr" || filepath.Ext(file) == ".cbz" {
+ log.Println("Comic Book Archive!")
+ openArchive(file)
+ return
+ }
+ newBrowse(file)
+}
+
+func openArchive(path string) {
+ r, err := zip.OpenReader(path)
+ if err != nil {
+ log.Println(err)
+ return
+ }
+ clearFileList()
+ directoryState.images = []imagefile{}
+ for _, f := range r.File {
+ log.Println(f.FileInfo().Name())
+ if f.FileInfo().IsDir() {
+ continue
+ }
+ if f.FileInfo().Name()[0] == '.' {
+ continue
+ }
+ reader, err := f.Open()
+ if err != nil {
+ log.Println(err)
+ continue
+ }
+ i, err := decode(reader, f.FileInfo().Name())
+ if err != nil {
+ log.Println(err)
+ continue
+ }
+ directoryState.images = append(directoryState.images, imagefile{
+ contents: &i,
+ filename: f.FileInfo().Name(),
+ })
+ insertIntoFileList(f.FileInfo().Name())
+ }
+ moveSelectionInFileList(0)
+ updateImage(directoryState.images[0].filename)
}
func newDirectory() {
@@ -102,12 +164,12 @@ func newBrowse(file string) {
})
// ...that way we only have to do this loop once.
clearFileList()
- directoryState.images = []string{}
+ directoryState.images = []imagefile{}
i := 0
for _, v := range dirfiles {
if filetypes.IsImage(v) {
- directoryState.images = append(directoryState.images, v.Name())
- insertIntoFileList(directoryState.images[i])
+ directoryState.images = append(directoryState.images, imagefile{filename: v.Name()})
+ insertIntoFileList(directoryState.images[i].filename)
if v.Name() == filepath.Base(file) {
directoryState.i = i
moveSelectionInFileList(i)
@@ -121,24 +183,28 @@ func newBrowse(file string) {
func updateImage(file string) {
var i image.Image
- f, err := os.Open(file)
+ entry, index, err := directoryState.imageWithFilename(filepath.Base(file))
if err != nil {
- log.Printf("error opening image: %v", err)
+ log.Println(err.Error())
return
}
- defer f.Close()
+ if entry.contents != nil {
+ fmt.Printf("loaded %s from cache\n", file)
+ i = *entry.contents
+ } else {
+ f, err := os.Open(file)
+ if err != nil {
+ log.Printf("error opening image: %v", err)
+ return
+ }
+ defer f.Close()
- ext := strings.ToLower(strings.TrimPrefix(filepath.Ext(file), "."))
- if checkErr(imaging.FormatFromExtension(ext)) {
- i, err = imaging.Decode(f, imaging.AutoOrientation(true))
- } else if ext == "webp" {
- i, err = webp.Decode(f)
- } else if ext == "tga" {
- i, err = tga.Decode(f)
- }
- if err != nil {
- log.Printf("error decoding image: %v", err)
- return
+ i, err = decode(f, file)
+ if err != nil {
+ log.Printf("error decoding image: %v", err)
+ return
+ }
+ directoryState.setImage(index, &i)
}
i = imaging.Fit(i,
// -50 to give some space to breathe around the edges
@@ -149,6 +215,18 @@ func updateImage(file string) {
repaint(filepath.Base(file), tk.Data(i))
}
+func decode(f io.Reader, name string) (image.Image, error) {
+ ext := strings.ToLower(strings.TrimPrefix(filepath.Ext(name), "."))
+ if checkErr(imaging.FormatFromExtension(ext)) {
+ return imaging.Decode(f, imaging.AutoOrientation(true))
+ } else if ext == "webp" {
+ return webp.Decode(f)
+ } else if ext == "tga" {
+ return tga.Decode(f)
+ }
+ return image.Black, fmt.Errorf("could not parse image")
+}
+
func repaint(name string, data tk.Opt) {
// TODO: sometimes, when going from a big image to a smaller one,
// the window remains the same height as the big image,
@@ -229,7 +307,7 @@ func constructFileList() {
}))
clearFileList()
for i := range directoryState.images {
- insertIntoFileList(directoryState.images[i])
+ insertIntoFileList(directoryState.images[i].filename)
if directoryState.i == i {
moveSelectionInFileList(i)
}