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