add cbz support
This commit is contained in:
		@@ -197,4 +197,60 @@
 | 
			
		||||
				<key>LSTypeIsPackage</key>
 | 
			
		||||
				<false/>
 | 
			
		||||
			</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>
 | 
			
		||||
@@ -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 {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										108
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										108
									
								
								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,6 +183,15 @@ func newBrowse(file string) {
 | 
			
		||||
func updateImage(file string) {
 | 
			
		||||
	var i image.Image
 | 
			
		||||
 | 
			
		||||
	entry, index, err := directoryState.imageWithFilename(filepath.Base(file))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Println(err.Error())
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	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)
 | 
			
		||||
@@ -128,18 +199,13 @@ func updateImage(file string) {
 | 
			
		||||
		}
 | 
			
		||||
		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)
 | 
			
		||||
	}
 | 
			
		||||
		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
 | 
			
		||||
		must(strconv.Atoi(tk.WinfoScreenWidth(tk.App)))-50,
 | 
			
		||||
@@ -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)
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user