diff --git a/.gitignore b/.gitignore index ebc9a5a..2b8d69b 100644 --- a/.gitignore +++ b/.gitignore @@ -35,5 +35,7 @@ pnpm-debug.log* !.yarn/versions .pnp.* -# blog -src/content/blog +# blog, meta +src/content/blog/* +Matomo.astro +src/pages/pages/* diff --git a/README.md b/README.md index 9f35789..f650606 100644 --- a/README.md +++ b/README.md @@ -20,13 +20,14 @@ The website will be built to the `./dist` folder. ## Blogging with Joplin -You can use Joplin to write and manageyour blog posts, instead of just placing the Markdown files in the +You can use Joplin to write and manage your blog posts, instead of just placing the Markdown files in the `src/content/blog` folder. 1. Install [Joplin](https://joplinapp.org/) 2. Start the Web Clipper Service: Tools > Options > Web Clipper > Start Web Clipper Service 3. Run `npm run joplin` 4. Allow the request for an API token on the Joplin app + - You can also place the Joplin token in an `.env` file in the format `JOPLIN_KEY=your_token`. The script will look for a notebook named `Blog`. It will then download all notes from that notebook, alongside their attachments, and place them in the `src/content/blog` folder. @@ -46,6 +47,22 @@ In order, to have an ogImage (also known as article cover): ``` Note the `.` (dot) instead of `:` (colon)! +## Uploading to WebDav + +I have found that a quick and easy way to deploy the website is via WebDav and compatible software on the server side, like +[this](https://github.com/mholt/caddy-webdav) plugin for Caddy. + +To simplify uploading to WebDav, I have created a script, which can be run with `npm run upload`. + +You have to set the following environment variables: +- `WEBDAV_ENDPOINT`: The URL of the WebDav server, e.g. `https://example.com/webdav/` +- `WEBDAV_USERNAME`: The username for the WebDav server +- `WEBDAV_PASSWORD`: The password for the WebDav server +- `WEBDAV_PATH`: The path to the folder on the server, e.g. `/public_html/` (default: `/`) + +The script will upload the `./dist` folder, so make sure you run `npm run build` before the upload script. +Note that running the script will clear the remote folder before uploading the files. + ## License The original [Astro Paper](https://github.com/satnaing/astro-paper) is licensed under the MIT License, Copyright © 2025 diff --git a/package-lock.json b/package-lock.json index 37dd0cd..542f094 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,7 +25,8 @@ "sass": "^1.77.2", "satori": "^0.10.11", "tailwindcss": "^3.4.1", - "typescript": "^5.4.5" + "typescript": "^5.4.5", + "webdav": "^5.8.0" }, "devDependencies": { "@astrojs/react": "^3.0.9", @@ -40,6 +41,7 @@ "astro-eslint-parser": "^0.16.2", "commitizen": "^4.3.0", "cz-conventional-changelog": "^3.3.0", + "dotenv": "^16.4.7", "eslint": "^8.56.0", "eslint-plugin-astro": "^0.31.3", "husky": "^8.0.3", @@ -739,6 +741,15 @@ "node": ">=6.9.0" } }, + "node_modules/@buttercup/fetch": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@buttercup/fetch/-/fetch-0.2.1.tgz", + "integrity": "sha512-sCgECOx8wiqY8NN1xN22BqqKzXYIG2AicNLlakOAI4f0WgyLVUbAigMf8CZhBtJxdudTcB1gD5lciqi44jwJvg==", + "license": "MIT", + "optionalDependencies": { + "node-fetch": "^3.3.0" + } + }, "node_modules/@commitlint/config-validator": { "version": "17.6.7", "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-17.6.7.tgz", @@ -4236,6 +4247,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/byte-length/-/byte-length-1.0.2.tgz", + "integrity": "sha512-ovBpjmsgd/teRmgcPh23d4gJvxDoXtAzEL9xTfMU8Yc2kqCDb7L9jAG0XHl1nzuGl+h3ebCIF1i62UFyA9V/2Q==", + "license": "MIT" + }, "node_modules/cachedir": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", @@ -4365,6 +4382,15 @@ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, "node_modules/cheerio": { "version": "1.0.0-rc.12", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", @@ -4987,6 +5013,15 @@ "node": ">= 8" } }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, "node_modules/css-background-parser": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/css-background-parser/-/css-background-parser-0.1.0.tgz", @@ -5120,6 +5155,15 @@ "@commitlint/load": ">6.1.1" } }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -5470,6 +5514,19 @@ "tslib": "^2.0.3" } }, + "node_modules/dotenv": { + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/dset": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.3.tgz", @@ -6154,21 +6211,18 @@ "dev": true }, "node_modules/fast-xml-parser": { - "version": "4.2.7", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.7.tgz", - "integrity": "sha512-J8r6BriSLO1uj2miOk1NW0YVm8AGOOu3Si2HQp/cSmo6EA4m3fcwu2WKjJ4RK9wMLBtg69y1kS8baDiQBR41Ig==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.3.tgz", + "integrity": "sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==", "funding": [ - { - "type": "paypal", - "url": "https://paypal.me/naturalintelligence" - }, { "type": "github", "url": "https://github.com/sponsors/NaturalIntelligence" } ], + "license": "MIT", "dependencies": { - "strnum": "^1.0.5" + "strnum": "^1.1.1" }, "bin": { "fxparser": "src/cli/cli.js" @@ -6190,6 +6244,29 @@ "pend": "~1.2.0" } }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, "node_modules/fflate": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz", @@ -6333,6 +6410,18 @@ "node": ">=8" } }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/fraction.js": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.6.tgz", @@ -6852,6 +6941,12 @@ "node": ">=0.10.0" } }, + "node_modules/hot-patcher": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hot-patcher/-/hot-patcher-2.0.1.tgz", + "integrity": "sha512-ECg1JFG0YzehicQaogenlcs2qg6WsXQsxtnbr1i696u5tLUjtJdQAh0u2g0Q5YV45f263Ta1GnUJsc8WIfJf4Q==", + "license": "MIT" + }, "node_modules/html-escaper": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz", @@ -7654,6 +7749,12 @@ "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==" }, + "node_modules/layerr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/layerr/-/layerr-3.0.0.tgz", + "integrity": "sha512-tv754Ki2dXpPVApOrjTyRo4/QegVb9eVFq4mjqp4+NM5NaX7syQvN5BBNfV/ZpAHCEHV24XdUVrBAoka4jt3pA==", + "license": "MIT" + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -8433,6 +8534,23 @@ "node": ">= 18" } }, + "node_modules/md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "license": "BSD-3-Clause", + "dependencies": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, + "node_modules/md5/node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "license": "MIT" + }, "node_modules/mdast-util-definitions": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-6.0.0.tgz", @@ -9505,6 +9623,12 @@ "node": ">=0.10.0" } }, + "node_modules/nested-property": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/nested-property/-/nested-property-4.0.0.tgz", + "integrity": "sha512-yFehXNWRs4cM0+dz7QxCd06hTbWbSkV0ISsqBfkntU6TOY4Qm3Q88fRRLOddkGh2Qq6dZvnKVAahfhjcUvLnyA==", + "license": "MIT" + }, "node_modules/nlcst-to-string": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-3.1.1.tgz", @@ -9545,6 +9669,43 @@ "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", "optional": true }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, "node_modules/node-releases": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", @@ -10050,6 +10211,12 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "node_modules/path-posix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/path-posix/-/path-posix-1.0.0.tgz", + "integrity": "sha512-1gJ0WpNIiYcQydgg3Ed8KzvIqTsDpNwq+cjBCssvBtuTWjEqY1AW+i+OepiEMqDCzyro9B2sLAe4RBPajMYFiA==", + "license": "ISC" + }, "node_modules/path-to-regexp": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", @@ -10690,6 +10857,12 @@ "node": ">=6" } }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "license": "MIT" + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -11033,6 +11206,12 @@ "node": ">=0.10.0" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT" + }, "node_modules/resolve": { "version": "1.22.4", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", @@ -12265,9 +12444,16 @@ } }, "node_modules/strnum": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", - "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.1.2.tgz", + "integrity": "sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" }, "node_modules/strtok3": { "version": "7.0.0", @@ -13175,6 +13361,25 @@ "punycode": "^2.1.0" } }, + "node_modules/url-join": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz", + "integrity": "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -13897,6 +14102,76 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/webdav": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webdav/-/webdav-5.8.0.tgz", + "integrity": "sha512-iuFG7NamJ41Oshg4930iQgfIpRrUiatPWIekeznYgEf2EOraTRcDPTjy7gIOMtkdpKTaqPk1E68NO5PAGtJahA==", + "license": "MIT", + "dependencies": { + "@buttercup/fetch": "^0.2.1", + "base-64": "^1.0.0", + "byte-length": "^1.0.2", + "entities": "^6.0.0", + "fast-xml-parser": "^4.5.1", + "hot-patcher": "^2.0.1", + "layerr": "^3.0.0", + "md5": "^2.3.0", + "minimatch": "^9.0.5", + "nested-property": "^4.0.0", + "node-fetch": "^3.3.2", + "path-posix": "^1.0.0", + "url-join": "^5.0.0", + "url-parse": "^1.5.10" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/webdav/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/webdav/node_modules/entities": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.0.tgz", + "integrity": "sha512-aKstq2TDOndCn4diEyp9Uq/Flu2i1GlLkc6XIDQSDMuaFE3OPW5OphLCyQ5SpSJZTb4reN+kTcYru5yIfXoRPw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/webdav/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/whatwg-encoding": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", diff --git a/package.json b/package.json index 67286b0..101f668 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ "cz": "cz", "prepare": "husky install", "lint": "eslint .", - "joplin": "node src/utils/joplin.js" + "joplin": "node src/utils/joplin.mjs", + "upload": "node src/utils/upload.mjs" }, "dependencies": { "@astrojs/check": "^0.7.0", @@ -33,7 +34,8 @@ "sass": "^1.77.2", "satori": "^0.10.11", "tailwindcss": "^3.4.1", - "typescript": "^5.4.5" + "typescript": "^5.4.5", + "webdav": "^5.8.0" }, "devDependencies": { "@astrojs/react": "^3.0.9", @@ -48,6 +50,7 @@ "astro-eslint-parser": "^0.16.2", "commitizen": "^4.3.0", "cz-conventional-changelog": "^3.3.0", + "dotenv": "^16.4.7", "eslint": "^8.56.0", "eslint-plugin-astro": "^0.31.3", "husky": "^8.0.3", diff --git a/src/components/Matomo.astro b/src/components/Matomo.astro index a8f7e7c..8324dee 100644 --- a/src/components/Matomo.astro +++ b/src/components/Matomo.astro @@ -1,12 +1 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/src/utils/joplin.js b/src/utils/joplin.mjs similarity index 94% rename from src/utils/joplin.js rename to src/utils/joplin.mjs index 98d67a3..d157435 100644 --- a/src/utils/joplin.js +++ b/src/utils/joplin.mjs @@ -1,6 +1,12 @@ -const http = require('node:http'); -const fs = require('fs'); -const path = require('path'); +import dotenv from 'dotenv'; +dotenv.config(); + +import http from 'node:http'; +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); async function fetch(url, method = "GET") { return new Promise((resolve) => { @@ -172,16 +178,18 @@ async function clearBlogFolder() { } async function main() { - console.log("Finding JoplinClipperServer port..."); let host = "http://localhost:" + await findPort(); - let apiToken = await authenticate(host); - //let apiToken = ""; + + let apiToken = process.env.JOPLIN_KEY; + if (!apiToken) { + apiToken = await authenticate(host); + } + let notes = await getNotebookNotes(apiToken, host); await clearBlogFolder(); for(let noteId of notes) { - let noteBody = await getNoteBody(apiToken, host, noteId); let slug = await getNoteSlug(noteBody); diff --git a/src/utils/upload.mjs b/src/utils/upload.mjs new file mode 100644 index 0000000..76bec24 --- /dev/null +++ b/src/utils/upload.mjs @@ -0,0 +1,96 @@ +import dotenv from 'dotenv'; +dotenv.config(); + +import { createClient } from 'webdav'; +import fs from 'fs'; +import path from 'path'; + +const client = createClient( + process.env.WEBDAV_ENDPOINT, + { + username: process.env.WEBDAV_USERNAME, + password: process.env.WEBDAV_PASSWORD, + maxBodyLength: Infinity, + maxContentLength: Infinity, + headers: { + Accept: "*/*", + Connection: "keep-alive" + } + } +); + +async function createDirectoryIfNotExist(remotePath) { + try { + const exists = await client.exists(remotePath); + if (!exists) { + await client.createDirectory(remotePath); + } + } catch (error) { + if (error.status !== 409 && error.status !== 405) { + throw error; + } + } +} + +async function uploadDirectory(localPath, remoteBasePath) { + try { + const items = fs.readdirSync(localPath, { withFileTypes: true }); + + for (const item of items) { + const localItemPath = path.join(localPath, item.name); + const remoteItemPath = path.posix.join(remoteBasePath, item.name); + + if (item.isDirectory()) { + // Create directory on WebDAV server + await createDirectoryIfNotExist(remoteItemPath); + console.log(`Verified directory: ${remoteItemPath}`); + await uploadDirectory(localItemPath, remoteItemPath); + } else { + // Upload file + console.log(`Uploading file: ${remoteItemPath}`); + const content = fs.readFileSync(localItemPath); + await client.putFileContents(remoteItemPath, content); + } + } + } catch (error) { + console.error(`Error processing ${localPath}:`, error.message); + throw error; + } +} + +async function clearFolder(remotePath) { + try { + const items = await client.getDirectoryContents(remotePath); + for (const item of items) { + if (item.basename !== '..') { + const itemPath = path.posix.join(remotePath, item.basename); + await client.deleteFile(itemPath); + } + } + } catch (error) { + console.error('Error clearing root folder:', error.message); + throw error; + } +} + +// Usage example +async function main() { + const localDir = './dist'; + let remoteDir = process.env.WEBDAV_REMOTE_DIR; + if(remoteDir === undefined) { + remoteDir = '/'; + } + + try { + // Clear root folder + await clearFolder(remoteDir); + + // Upload new content + await uploadDirectory(localDir, remoteDir); + console.log('Directory upload complete'); + } catch (error) { + console.error('Upload failed:', error.message); + } +} + +main();