.IMAGE — extensions removed from AllowedExtensions (scan gate), bookExtensions, MimeTypes and sync/format.go maps: .doc/.lit files are no longer scanned or indexed. classifyFormatGroup gains the RTF and PDB reflowable arms that were missing when those rungs shipped (rows only reclassify on creation). Scanner docs updated. DOC + LIT have no credible JS tooling (mammoth is docx-only; LIT needs LZX and its DRM variants are dead) and text-extraction-only support would misrepresent what the reader can do. Verified: probe .doc/.lit files watched but never scanned; probe .txt control scanned; TestClassifyFormatGroup extended and passing. Docs change granted in-session by the user (extensions + format docs).
129 lines
3.1 KiB
Go
129 lines
3.1 KiB
Go
package sync
|
|
|
|
import (
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
// FormatGroup represents the three main format categories
|
|
type FormatGroup string
|
|
|
|
const (
|
|
FormatGroupReflowable FormatGroup = "reflowable"
|
|
FormatGroupFixedLayout FormatGroup = "fixed_layout"
|
|
FormatGroupComicArchive FormatGroup = "comic_archive"
|
|
FormatGroupUnknown FormatGroup = "unknown"
|
|
)
|
|
|
|
// MimeType mappings for common ebook formats
|
|
var mimeTypes = map[string]string{
|
|
".epub": "application/epub+zip",
|
|
".mobi": "application/x-mobipocket-ebook",
|
|
".azw": "application/x-mobipocket-ebook",
|
|
".azw3": "application/vnd.amazon.mobi8-ebook",
|
|
".pdf": "application/pdf",
|
|
".djvu": "image/vnd.djvu",
|
|
".cbz": "application/x-cbz",
|
|
".cbr": "application/x-cbr",
|
|
".cb7": "application/x-cb7",
|
|
".cbt": "application/x-cbt",
|
|
".fb2": "application/x-fictionbook+xml",
|
|
".txt": "text/plain",
|
|
".rtf": "application/rtf",
|
|
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
".pdb": "application/vnd.palm",
|
|
".prc": "application/vnd.palm",
|
|
}
|
|
|
|
// ReflowableFormats are formats that support text reflow
|
|
var ReflowableFormats = map[string]bool{
|
|
".epub": true,
|
|
".mobi": true,
|
|
".azw": true,
|
|
".azw3": true,
|
|
".fb2": true,
|
|
".txt": true,
|
|
".rtf": true,
|
|
".docx": true,
|
|
".pdb": true,
|
|
".prc": true,
|
|
}
|
|
|
|
// FixedLayoutFormats are formats with fixed page layouts
|
|
var FixedLayoutFormats = map[string]bool{
|
|
".pdf": true,
|
|
".djvu": true,
|
|
}
|
|
|
|
// ComicArchiveFormats are comic archive formats
|
|
var ComicArchiveFormats = map[string]bool{
|
|
".cbz": true,
|
|
".cbr": true,
|
|
".cb7": true,
|
|
".cbt": true,
|
|
}
|
|
|
|
// DetectFormatGroup determines the format group based on mimetype and file path
|
|
func DetectFormatGroup(mimetype string, filePath string) FormatGroup {
|
|
ext := strings.ToLower(filepath.Ext(filePath))
|
|
|
|
// Check by mimetype first
|
|
switch mimetype {
|
|
case "application/epub+zip",
|
|
"application/x-mobipocket-ebook",
|
|
"application/vnd.amazon.mobi8-ebook",
|
|
"application/x-fictionbook+xml",
|
|
"text/plain":
|
|
return FormatGroupReflowable
|
|
|
|
case "application/pdf",
|
|
"image/vnd.djvu":
|
|
return FormatGroupFixedLayout
|
|
|
|
case "application/x-cbr",
|
|
"application/x-cbz",
|
|
"application/x-cb7",
|
|
"application/x-cbt":
|
|
return FormatGroupComicArchive
|
|
}
|
|
|
|
// Fall back to file extension
|
|
if ReflowableFormats[ext] {
|
|
return FormatGroupReflowable
|
|
}
|
|
|
|
if FixedLayoutFormats[ext] {
|
|
return FormatGroupFixedLayout
|
|
}
|
|
|
|
if ComicArchiveFormats[ext] {
|
|
return FormatGroupComicArchive
|
|
}
|
|
|
|
return FormatGroupUnknown
|
|
}
|
|
|
|
// GetMimeType returns the mimetype for a given file extension
|
|
func GetMimeType(filePath string) string {
|
|
ext := strings.ToLower(filepath.Ext(filePath))
|
|
if mt, ok := mimeTypes[ext]; ok {
|
|
return mt
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// IsReflowable checks if a format is reflowable
|
|
func IsReflowable(formatGroup FormatGroup) bool {
|
|
return formatGroup == FormatGroupReflowable
|
|
}
|
|
|
|
// HasFixedLayout checks if a format has fixed layout
|
|
func HasFixedLayout(formatGroup FormatGroup) bool {
|
|
return formatGroup == FormatGroupFixedLayout
|
|
}
|
|
|
|
// IsComicArchive checks if a format is a comic archive
|
|
func IsComicArchive(formatGroup FormatGroup) bool {
|
|
return formatGroup == FormatGroupComicArchive
|
|
}
|