diff --git a/bun.lock b/bun.lock index f105585..ab0d7fd 100644 --- a/bun.lock +++ b/bun.lock @@ -6,6 +6,7 @@ "name": "steve-photo-svelte", "dependencies": { "exifr": "^7.1.3", + "feed": "^5.2.0", "from": "^0.1.7", "import": "^0.0.6", }, @@ -300,6 +301,8 @@ "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + "feed": ["feed@5.2.0", "", { "dependencies": { "xml-js": "^1.6.11" } }, "sha512-hgH6CCb+7+0c8PBlakI2KubG6R+Rb1MhpNcdvqUXZTBwBHf32piwY255diAkAmkGZ6AWlywOU88AkOgP9q8Rdw=="], + "from": ["from@0.1.7", "", {}, "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g=="], "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], @@ -372,6 +375,8 @@ "sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="], + "sax": ["sax@1.4.4", "", {}, "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw=="], + "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], "set-cookie-parser": ["set-cookie-parser@2.7.2", "", {}, "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw=="], @@ -418,6 +423,8 @@ "ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="], + "xml-js": ["xml-js@1.6.11", "", { "dependencies": { "sax": "^1.2.4" }, "bin": { "xml-js": "./bin/cli.js" } }, "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g=="], + "youch": ["youch@4.1.0-beta.10", "", { "dependencies": { "@poppinss/colors": "^4.1.5", "@poppinss/dumper": "^0.6.4", "@speed-highlight/core": "^1.2.7", "cookie": "^1.0.2", "youch-core": "^0.3.3" } }, "sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ=="], "youch-core": ["youch-core@0.3.3", "", { "dependencies": { "@poppinss/exception": "^1.2.2", "error-stack-parser-es": "^1.0.5" } }, "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA=="], diff --git a/package.json b/package.json index 0c6e869..f8275c2 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ }, "dependencies": { "exifr": "^7.1.3", + "feed": "^5.2.0", "from": "^0.1.7", "import": "^0.0.6" } diff --git a/src/lib/feed.ts b/src/lib/feed.ts new file mode 100644 index 0000000..c4b4156 --- /dev/null +++ b/src/lib/feed.ts @@ -0,0 +1,32 @@ +import type { ImageItem } from "$lib/types"; + +const R2_BASE_URL = "https://r2.steve.photo"; + +export async function getPhotos(platform: App.Platform | undefined): Promise { + const db = platform?.env?.DB; + + if (!db) { + return []; + } + + const result = await db.prepare("SELECT * FROM photos ORDER BY date DESC").all(); + + const photos: ImageItem[] = result.results.map((row: Record) => ({ + slug: row.slug as string, + title: row.title as string, + date: row.date as string, + image: `${R2_BASE_URL}/${row.image_key}`, + thumb: `${R2_BASE_URL}/${row.thumb_key}`, + type: row.type as string, + camera: row.camera as string, + lens: row.lens as string, + aperture: row.aperture as string, + exposure: row.exposure as string, + focalLength: row.focal_length as string, + iso: row.iso as string, + make: row.make as string, + tags: [], + })); + + return photos; +} diff --git a/src/routes/rss.xml/+server.ts b/src/routes/rss.xml/+server.ts new file mode 100644 index 0000000..18183db --- /dev/null +++ b/src/routes/rss.xml/+server.ts @@ -0,0 +1,50 @@ +import { Feed } from "feed"; +import { getPhotos } from "$lib/feed"; +import type { RequestHandler } from "./$types"; + +export const GET: RequestHandler = async ({ platform }) => { + const feed = new Feed({ + title: "steve.photo", + description: "Personal photography portolio of Steve Simkins", + id: "https://steve.photo", + link: "https://steve.photo/", + language: "en", + favicon: "https://steve.photo/favicon.ico", + copyright: `Copyright ${new Date().getFullYear().toString()}, Steve Simkins`, + feedLinks: { + rss: "https://steve.photo/rss.xml", + }, + author: { + name: "Steve Simkins", + email: "contact@stevedylan.dev", + link: "https://stevedylan.dev", + }, + ttl: 60, + }); + + const photos = await getPhotos(platform); + + for (const photo of photos) { + feed.addItem({ + title: photo.title, + id: `https://steve.photo/photo/${photo.slug}`, + link: `https://steve.photo/photo/${photo.slug}`, + date: new Date(photo.date), + image: photo.image, + author: [ + { + name: "Steve Simkins", + email: "contact@stevedylan.dev", + link: "https://stevedylan.dev", + }, + ], + content: `${photo.title}

Camera: ${photo.camera} | Lens: ${photo.lens} | ${photo.aperture} | ${photo.exposure} | ISO ${photo.iso}

`, + }); + } + + return new Response(feed.rss2(), { + headers: { + "Content-Type": "application/xml; charset=utf-8", + }, + }); +};