Smarter ZIP download naming.
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
import { useMainStore } from '@/stores/main'
|
||||
import { apiFetch } from '@/repositories/Client'
|
||||
import type { SelectedItems } from '@/repositories/Document'
|
||||
import { zipName } from '@/utils/fileutil'
|
||||
import { reactive } from 'vue';
|
||||
|
||||
const store = useMainStore()
|
||||
@@ -106,7 +107,6 @@ const filesystemdl = async (sel: SelectedItems, handle: FileSystemDirectoryHandl
|
||||
++store.dprogress.fileidx
|
||||
const reader = res.body.getReader()
|
||||
await writable.truncate(0)
|
||||
store.error = "Direct download."
|
||||
store.dprogress.tlast = Date.now()
|
||||
while (true) {
|
||||
const { value, done } = await reader.read()
|
||||
@@ -136,7 +136,7 @@ const download = async () => {
|
||||
console.log('Download', sel)
|
||||
if (sel.keys.length === 0) {
|
||||
console.warn('Attempted download but no files found. Missing selected keys:', sel.missing)
|
||||
store.error = 'No existing files selected'
|
||||
store.showToast('No existing files selected')
|
||||
store.selected.clear()
|
||||
return
|
||||
}
|
||||
@@ -144,7 +144,7 @@ const download = async () => {
|
||||
const files = sel.recursive.filter(([rel, full, doc]) => !doc.dir)
|
||||
if (files.length === 1) {
|
||||
store.selected.clear()
|
||||
store.error = "Single file via browser downloads"
|
||||
store.showToast(`Downloading ${files[0]![0].split('/').pop()}`)
|
||||
return linkdl(`/files/${files[0]![1]}`)
|
||||
}
|
||||
// Use FileSystem API if multiple files and the browser supports it
|
||||
@@ -164,9 +164,10 @@ const download = async () => {
|
||||
}
|
||||
// Otherwise, zip and download
|
||||
console.log("Falling back to zip download")
|
||||
const name = sel.keys.length === 1 ? sel.docs[sel.keys[0]!]!.name : 'download'
|
||||
const items = sel.keys.map(k => sel.docs[k]!)
|
||||
const name = zipName(items)
|
||||
linkdl(`/zip/${Array.from(sel.keys).join('+')}/${name}.zip`)
|
||||
store.error = "Downloading as ZIP via browser downloads"
|
||||
store.showToast(`Downloading ${name}.zip`)
|
||||
store.selected.clear()
|
||||
}
|
||||
|
||||
|
||||
@@ -6,3 +6,44 @@ export const exists = (path: string[]) => {
|
||||
const p = path.join('/')
|
||||
return store.document.some(doc => (doc.loc ? `${doc.loc}/${doc.name}` : doc.name) === p)
|
||||
}
|
||||
|
||||
/** Strip file extension intelligently (handles .tar.gz, name.with.dots.pdf, etc.) */
|
||||
export const stripExt = (name: string): string => {
|
||||
// Common compound extensions
|
||||
const compoundExts = ['.tar.gz', '.tar.bz2', '.tar.xz', '.tar.zst']
|
||||
const lower = name.toLowerCase()
|
||||
for (const ext of compoundExts) {
|
||||
if (lower.endsWith(ext)) return name.slice(0, -ext.length)
|
||||
}
|
||||
// Regular extension: only strip if the extension looks like one (2-5 chars, alphanumeric)
|
||||
const lastDot = name.lastIndexOf('.')
|
||||
if (lastDot > 0) {
|
||||
const ext = name.slice(lastDot + 1)
|
||||
if (ext.length >= 2 && ext.length <= 5 && /^[a-zA-Z0-9]+$/.test(ext)) {
|
||||
return name.slice(0, lastDot)
|
||||
}
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
/** Generate a sensible zip filename for a selection of items */
|
||||
export const zipName = (items: { name: string; loc: string }[]): string => {
|
||||
const names = items.map(d => d.name)
|
||||
if (names.length === 1) {
|
||||
// Single item - use its name
|
||||
return stripExt(names[0]!)
|
||||
}
|
||||
// Check if all items share the same direct parent folder
|
||||
const locs = items.map(d => d.loc)
|
||||
const sameLoc = locs.every(loc => loc === locs[0])
|
||||
if (sameLoc && locs[0]) {
|
||||
// All items in same folder - use folder name
|
||||
return locs[0].split('/').pop()!
|
||||
}
|
||||
if (names.length <= 3) {
|
||||
// Few items from different folders - join basenames with dot
|
||||
return names.map(stripExt).join('.')
|
||||
}
|
||||
// Many items from different folders - first basename + indicator
|
||||
return `${stripExt(names[0]!)}.etc`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user