74 lines
3 KiB
JavaScript
74 lines
3 KiB
JavaScript
#!/usr/bin/env node
|
|
import { mkdirSync, writeFileSync } from 'node:fs'
|
|
import { basename, join } from 'node:path'
|
|
import { PROPFIND_BODY } from '#import-recipes/webdav/PROPFIND_BODY.js'
|
|
import { listOdtHrefs } from '#import-recipes/webdav/listOdtHrefs.js'
|
|
import { parseFetchArguments } from '#import-recipes/webdav/parseFetchArguments.js'
|
|
|
|
const USAGE = `Usage: NEXTCLOUD_APP_PASSWORD=... node fetchOdtFromNextcloud.js --server <url> --user <name> --folder <path> [--out odt]
|
|
|
|
Downloads the .odt files of one Nextcloud folder, so importRecipes.js can read
|
|
them from disk. Optional: copying the files by hand does the same job.
|
|
The password must be an app password, never the account password.`
|
|
|
|
// Optional companion to the importer, and the only other place this tool talks
|
|
// to the network. It downloads, and nothing else: no parsing, no model call.
|
|
async function main() {
|
|
const { server, user, folder, out, problems } = parseFetchArguments(process.argv.slice(2))
|
|
const password = process.env.NEXTCLOUD_APP_PASSWORD ?? ''
|
|
if (problems.length > 0 || !server || !user || !folder || !password) {
|
|
for (const problem of problems) console.error(problem)
|
|
if (!password) console.error('NEXTCLOUD_APP_PASSWORD is not set')
|
|
console.error(`\n${USAGE}`)
|
|
return 1
|
|
}
|
|
const origin = server.startsWith('http') ? server : `https://${server}`
|
|
const path = folder.split('/').filter(Boolean).map(encodeURIComponent).join('/')
|
|
const folderUrl = `${origin.replace(/\/+$/, '')}/remote.php/dav/files/${encodeURIComponent(user)}/${path}/`
|
|
const authorization = `Basic ${Buffer.from(`${user}:${password}`, 'utf8').toString('base64')}`
|
|
|
|
let hrefs = []
|
|
try {
|
|
const response = await fetch(folderUrl, {
|
|
method: 'PROPFIND',
|
|
headers: { authorization, depth: '1', 'content-type': 'application/xml' },
|
|
body: PROPFIND_BODY
|
|
})
|
|
if (!response.ok) {
|
|
console.error(`PROPFIND ${folderUrl} answered ${response.status}.`)
|
|
return 1
|
|
}
|
|
hrefs = listOdtHrefs(await response.text())
|
|
} catch (error) {
|
|
console.error(`PROPFIND ${folderUrl} failed: ${error.message}`)
|
|
return 1
|
|
}
|
|
if (hrefs.length === 0) {
|
|
console.error(`No .odt file in ${folder}.`)
|
|
return 1
|
|
}
|
|
|
|
mkdirSync(out, { recursive: true })
|
|
let failed = 0
|
|
for (const href of hrefs) {
|
|
const fileName = decodeURIComponent(basename(href))
|
|
const fileUrl = href.startsWith('http') ? href : `${new URL(folderUrl).origin}${href}`
|
|
try {
|
|
const response = await fetch(fileUrl, { headers: { authorization } })
|
|
if (!response.ok) {
|
|
console.error(`${fileName} - FAILED: HTTP ${response.status}`)
|
|
failed += 1
|
|
continue
|
|
}
|
|
writeFileSync(join(out, fileName), Buffer.from(await response.arrayBuffer()))
|
|
console.log(`${fileName} - downloaded`)
|
|
} catch (error) {
|
|
console.error(`${fileName} - FAILED: ${error.message}`)
|
|
failed += 1
|
|
}
|
|
}
|
|
console.log(`\n${hrefs.length - failed} downloaded, ${failed} failed, in ${out}/`)
|
|
return failed === 0 ? 0 : 1
|
|
}
|
|
|
|
process.exitCode = await main()
|