fix(scanner): classify .docx as reflowable — was landing format_group unknown
.docx is accepted for ingest but the format-group switch had no case for it, so every DOCX row stored format_group 'unknown' with is_reflowable=false. Extract the classification switch into a pure classifyFormatGroup helper with a table test, and classify .docx reflowable like the other reflowable text formats (.rtf/.doc stay out until they are readable client-side). Existing rows: dev alice (DOCX) reclassified by hand; production rows reclassify on rescan.
This commit is contained in:
@@ -974,30 +974,12 @@ func (s *MediaScanner) processMediaFile(ctx context.Context, path string) (bool,
|
|||||||
// Set format group, total characters, and chapter count
|
// Set format group, total characters, and chapter count
|
||||||
mimeType := s.getMimeType(path)
|
mimeType := s.getMimeType(path)
|
||||||
ext := strings.ToLower(filepath.Ext(path))
|
ext := strings.ToLower(filepath.Ext(path))
|
||||||
var formatGroup string
|
var epubIsFixedLayout bool
|
||||||
var isReflowable, hasFixedLayout bool
|
if ext == ".epub" {
|
||||||
switch ext {
|
|
||||||
case ".epub":
|
|
||||||
isFixed, fixedErr := s.DetectFixedLayoutEPUB(path)
|
isFixed, fixedErr := s.DetectFixedLayoutEPUB(path)
|
||||||
if fixedErr == nil && isFixed {
|
epubIsFixedLayout = fixedErr == nil && isFixed
|
||||||
formatGroup = "fixed_layout"
|
|
||||||
hasFixedLayout = true
|
|
||||||
} else {
|
|
||||||
formatGroup = "reflowable"
|
|
||||||
isReflowable = true
|
|
||||||
}
|
|
||||||
case ".mobi", ".azw", ".azw3", ".fb2", ".txt":
|
|
||||||
formatGroup = "reflowable"
|
|
||||||
isReflowable = true
|
|
||||||
case ".pdf", ".djvu":
|
|
||||||
formatGroup = "fixed_layout"
|
|
||||||
hasFixedLayout = true
|
|
||||||
case ".cbz", ".cbr", ".cb7", ".cbt":
|
|
||||||
formatGroup = "comic_archive"
|
|
||||||
hasFixedLayout = true
|
|
||||||
default:
|
|
||||||
formatGroup = "unknown"
|
|
||||||
}
|
}
|
||||||
|
formatGroup, isReflowable, hasFixedLayout := classifyFormatGroup(ext, epubIsFixedLayout)
|
||||||
err = s.db.UpdateMediaItemFormatGroup(ctx, database.UpdateMediaItemFormatGroupParams{
|
err = s.db.UpdateMediaItemFormatGroup(ctx, database.UpdateMediaItemFormatGroupParams{
|
||||||
ID: createdItem.ID,
|
ID: createdItem.ID,
|
||||||
FormatGroup: formatGroup,
|
FormatGroup: formatGroup,
|
||||||
@@ -3880,6 +3862,28 @@ func (s *MediaScanner) detectFormatType(filePath string) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// classifyFormatGroup maps a lowercased file extension to the format
|
||||||
|
// group and layout flags stored on the media item. `.epub` is passed in
|
||||||
|
// with its detected fixed-layout flag because that check needs the file
|
||||||
|
// itself.
|
||||||
|
func classifyFormatGroup(ext string, epubIsFixedLayout bool) (formatGroup string, isReflowable, hasFixedLayout bool) {
|
||||||
|
switch ext {
|
||||||
|
case ".epub":
|
||||||
|
if epubIsFixedLayout {
|
||||||
|
return "fixed_layout", false, true
|
||||||
|
}
|
||||||
|
return "reflowable", true, false
|
||||||
|
case ".mobi", ".azw", ".azw3", ".fb2", ".txt", ".docx":
|
||||||
|
return "reflowable", true, false
|
||||||
|
case ".pdf", ".djvu":
|
||||||
|
return "fixed_layout", false, true
|
||||||
|
case ".cbz", ".cbr", ".cb7", ".cbt":
|
||||||
|
return "comic_archive", false, true
|
||||||
|
default:
|
||||||
|
return "unknown", false, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// extractHashInfo calculates hash and extracts OPF identifiers for a file
|
// extractHashInfo calculates hash and extracts OPF identifiers for a file
|
||||||
func (s *MediaScanner) extractHashInfo(filePath string) (*HashInfo, *FormatInfo, error) {
|
func (s *MediaScanner) extractHashInfo(filePath string) (*HashInfo, *FormatInfo, error) {
|
||||||
// Calculate SHA-256
|
// Calculate SHA-256
|
||||||
|
|||||||
@@ -119,3 +119,34 @@ func TestProcessDirtyDirectories_CollectsReadyDirs(t *testing.T) {
|
|||||||
scanner.dirtyDirsMu.RUnlock()
|
scanner.dirtyDirsMu.RUnlock()
|
||||||
assert.Equal(t, 0, count, "Ready directory should be removed from dirty list")
|
assert.Equal(t, 0, count, "Ready directory should be removed from dirty list")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestClassifyFormatGroup(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
ext string
|
||||||
|
epubFixed bool
|
||||||
|
group string
|
||||||
|
reflow bool
|
||||||
|
fixed bool
|
||||||
|
}{
|
||||||
|
{"EPUB reflowable", ".epub", false, "reflowable", true, false},
|
||||||
|
{"EPUB fixed-layout", ".epub", true, "fixed_layout", false, true},
|
||||||
|
{"MOBI", ".mobi", false, "reflowable", true, false},
|
||||||
|
{"FB2", ".fb2", false, "reflowable", true, false},
|
||||||
|
{"TXT", ".txt", false, "reflowable", true, false},
|
||||||
|
{"DOCX (was unknown before the fix)", ".docx", false, "reflowable", true, false},
|
||||||
|
{"PDF", ".pdf", false, "fixed_layout", false, true},
|
||||||
|
{"DJVU", ".djvu", false, "fixed_layout", false, true},
|
||||||
|
{"CBZ", ".cbz", false, "comic_archive", false, true},
|
||||||
|
{"unrecognized extension", ".xyz", false, "unknown", false, false},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
group, reflow, fixed := classifyFormatGroup(tt.ext, tt.epubFixed)
|
||||||
|
if group != tt.group || reflow != tt.reflow || fixed != tt.fixed {
|
||||||
|
t.Errorf("classifyFormatGroup(%q, %v) = (%q, %v, %v), want (%q, %v, %v)",
|
||||||
|
tt.ext, tt.epubFixed, group, reflow, fixed, tt.group, tt.reflow, tt.fixed)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user