add cbz support
This commit is contained in:
@@ -197,4 +197,60 @@
|
|||||||
<key>LSTypeIsPackage</key>
|
<key>LSTypeIsPackage</key>
|
||||||
<false/>
|
<false/>
|
||||||
</dict>
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeExtensions</key>
|
||||||
|
<array>
|
||||||
|
<string>cbz</string>
|
||||||
|
<string>CBZ</string>
|
||||||
|
</array>
|
||||||
|
<key>CFBundleTypeIconFile</key>
|
||||||
|
<string>cbz.icns</string>
|
||||||
|
<key>CFBundleTypeMIMETypes</key>
|
||||||
|
<array>
|
||||||
|
<string>application/vnd.comicbook+zip</string>
|
||||||
|
<string>application/x-cbz</string>
|
||||||
|
</array>
|
||||||
|
<key>CFBundleTypeName</key>
|
||||||
|
<string>Comic Book Zip Archive</string>
|
||||||
|
<key>CFBundleTypeOSTypes</key>
|
||||||
|
<array>
|
||||||
|
<string>CBZ</string>
|
||||||
|
</array>
|
||||||
|
<key>CFBundleTypeRole</key>
|
||||||
|
<string>Viewer</string>
|
||||||
|
<key>LSItemContentTypes</key>
|
||||||
|
<array>
|
||||||
|
<string>in.yetaga.why.cbz</string>
|
||||||
|
</array>
|
||||||
|
<key>LSTypeIsPackage</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeExtensions</key>
|
||||||
|
<array>
|
||||||
|
<string>cbr</string>
|
||||||
|
<string>CBR</string>
|
||||||
|
</array>
|
||||||
|
<key>CFBundleTypeIconFile</key>
|
||||||
|
<string>cbr.icns</string>
|
||||||
|
<key>CFBundleTypeMIMETypes</key>
|
||||||
|
<array>
|
||||||
|
<string>application/vnd.comicbook-rar</string>
|
||||||
|
<string>application/x-cbr</string>
|
||||||
|
</array>
|
||||||
|
<key>CFBundleTypeName</key>
|
||||||
|
<string>Comic Book Rar Archive</string>
|
||||||
|
<key>CFBundleTypeOSTypes</key>
|
||||||
|
<array>
|
||||||
|
<string>CBR</string>
|
||||||
|
</array>
|
||||||
|
<key>CFBundleTypeRole</key>
|
||||||
|
<string>Viewer</string>
|
||||||
|
<key>LSItemContentTypes</key>
|
||||||
|
<array>
|
||||||
|
<string>in.yetaga.why.cbr</string>
|
||||||
|
</array>
|
||||||
|
<key>LSTypeIsPackage</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
</array>
|
</array>
|
@@ -84,6 +84,24 @@ var Valid = []FileDescription{
|
|||||||
OSTypes: []string{"WEBP"},
|
OSTypes: []string{"WEBP"},
|
||||||
ItemContentTypes: "org.webmproject.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 {
|
func GetTkTypes(fds []FileDescription) []tk.FileType {
|
||||||
|
120
main.go
120
main.go
@@ -1,9 +1,11 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"archive/zip"
|
||||||
_ "embed"
|
_ "embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -22,7 +24,12 @@ import (
|
|||||||
type state struct {
|
type state struct {
|
||||||
dir string
|
dir string
|
||||||
i int
|
i int
|
||||||
images []string
|
images []imagefile
|
||||||
|
}
|
||||||
|
|
||||||
|
type imagefile struct {
|
||||||
|
contents *image.Image
|
||||||
|
filename string
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:embed media/noise.png
|
//go:embed media/noise.png
|
||||||
@@ -41,7 +48,20 @@ var fileListBindVar = tk.Variable("FileList")
|
|||||||
var directoryState state
|
var directoryState state
|
||||||
|
|
||||||
func (d state) pathToImageAtIndex(i int) string {
|
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 {
|
func must[T any](t T, err error) T {
|
||||||
@@ -62,7 +82,49 @@ func newFileInDirectory() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// GetOpenFile returns an array split on spaces!
|
// 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() {
|
func newDirectory() {
|
||||||
@@ -102,12 +164,12 @@ func newBrowse(file string) {
|
|||||||
})
|
})
|
||||||
// ...that way we only have to do this loop once.
|
// ...that way we only have to do this loop once.
|
||||||
clearFileList()
|
clearFileList()
|
||||||
directoryState.images = []string{}
|
directoryState.images = []imagefile{}
|
||||||
i := 0
|
i := 0
|
||||||
for _, v := range dirfiles {
|
for _, v := range dirfiles {
|
||||||
if filetypes.IsImage(v) {
|
if filetypes.IsImage(v) {
|
||||||
directoryState.images = append(directoryState.images, v.Name())
|
directoryState.images = append(directoryState.images, imagefile{filename: v.Name()})
|
||||||
insertIntoFileList(directoryState.images[i])
|
insertIntoFileList(directoryState.images[i].filename)
|
||||||
if v.Name() == filepath.Base(file) {
|
if v.Name() == filepath.Base(file) {
|
||||||
directoryState.i = i
|
directoryState.i = i
|
||||||
moveSelectionInFileList(i)
|
moveSelectionInFileList(i)
|
||||||
@@ -121,24 +183,28 @@ func newBrowse(file string) {
|
|||||||
func updateImage(file string) {
|
func updateImage(file string) {
|
||||||
var i image.Image
|
var i image.Image
|
||||||
|
|
||||||
f, err := os.Open(file)
|
entry, index, err := directoryState.imageWithFilename(filepath.Base(file))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error opening image: %v", err)
|
log.Println(err.Error())
|
||||||
return
|
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), "."))
|
i, err = decode(f, file)
|
||||||
if checkErr(imaging.FormatFromExtension(ext)) {
|
if err != nil {
|
||||||
i, err = imaging.Decode(f, imaging.AutoOrientation(true))
|
log.Printf("error decoding image: %v", err)
|
||||||
} else if ext == "webp" {
|
return
|
||||||
i, err = webp.Decode(f)
|
}
|
||||||
} else if ext == "tga" {
|
directoryState.setImage(index, &i)
|
||||||
i, err = tga.Decode(f)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("error decoding image: %v", err)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
i = imaging.Fit(i,
|
i = imaging.Fit(i,
|
||||||
// -50 to give some space to breathe around the edges
|
// -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))
|
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) {
|
func repaint(name string, data tk.Opt) {
|
||||||
// TODO: sometimes, when going from a big image to a smaller one,
|
// TODO: sometimes, when going from a big image to a smaller one,
|
||||||
// the window remains the same height as the big image,
|
// the window remains the same height as the big image,
|
||||||
@@ -229,7 +307,7 @@ func constructFileList() {
|
|||||||
}))
|
}))
|
||||||
clearFileList()
|
clearFileList()
|
||||||
for i := range directoryState.images {
|
for i := range directoryState.images {
|
||||||
insertIntoFileList(directoryState.images[i])
|
insertIntoFileList(directoryState.images[i].filename)
|
||||||
if directoryState.i == i {
|
if directoryState.i == i {
|
||||||
moveSelectionInFileList(i)
|
moveSelectionInFileList(i)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user