Compare commits

...

19 Commits

Author SHA1 Message Date
2840715cb6 Add Twisted Spine, Gladys Books and Wine, and White Rabbit's Books
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-09-07 18:51:15 +00:00
5c6a07e87b Merge pull request 'Update dependency cheerio to v1.1.2' (#21) from renovate/cheerio-1.x-lockfile into main
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Reviewed-on: #21
2025-08-27 03:29:35 +00:00
cd0dd430c6 Merge pull request 'Update caddy Docker tag to v2.10.2' (#22) from renovate/caddy-2.x into main
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Reviewed-on: #22
2025-08-27 03:28:07 +00:00
115f5692e3 Update caddy Docker tag to v2.10.2
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-08-25 22:01:59 +00:00
45c625994b Update dependency cheerio to v1.1.2
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-08-22 16:02:24 +00:00
93aea2e385 All Shakespeare and Company stores have either closed or been taken over by The Strand.
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-08-09 20:08:33 +00:00
d5a43e291c Add the Fountain Bookshop
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-08-09 20:02:41 +00:00
f499b594da Merge pull request 'Update dependency cheerio to v1.1.0' (#20) from renovate/cheerio-1.x-lockfile into main
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Reviewed-on: #20
2025-06-09 01:22:02 +00:00
7beb704808 Update dependency cheerio to v1.1.0
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-06-08 20:01:29 +00:00
3f642f0a47 Merge pull request 'Update node Docker tag to v24' (#19) from renovate/node-24.x into main
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Reviewed-on: #19
2025-05-27 01:43:57 +00:00
c0450242ea Update node Docker tag to v24
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-05-06 22:01:54 +00:00
cb627abe06 Merge pull request 'Update caddy Docker tag to v2.10.0' (#18) from renovate/caddy-2.x into main
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Reviewed-on: #18
2025-04-22 13:27:41 +00:00
b56bcbc26d Update caddy Docker tag to v2.10.0
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-04-22 01:01:46 +00:00
d5f71fa043 correct canonical and sitemap with www
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-03-23 19:09:52 +00:00
0bde4eb0d1 restore meta description field
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-03-19 20:10:41 -04:00
22bad851e0 remove priority and changefreq from sitemap
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-03-19 20:07:30 -04:00
2c861f868a fix canonical tag
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-03-19 09:05:01 -04:00
a31c158cc5 Merge pull request 'add sitemap' (#17) from sitemap into main
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Reviewed-on: #17
2025-03-19 02:57:35 +00:00
78b35a7d83 add sitemap
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-03-18 22:56:41 -04:00
6 changed files with 280 additions and 111 deletions

View File

@@ -1,9 +1,9 @@
FROM node:22 AS builder
FROM node:24 AS builder
COPY . /src
WORKDIR /src
RUN npm install && node ./index.js
FROM caddy:2.9.1
FROM caddy:2.10.2
COPY --from=builder /src/build /usr/share/caddy

View File

@@ -1,13 +1,15 @@
import { load } from "cheerio";
import { readFile, writeFileSync, mkdirSync, cpSync, rmSync } from "fs";
import process from "child_process";
import { simpleSitemapAndIndex } from "sitemap";
import stores from "./stores.json" with { type: "json" };
function mkDir(path) {
try {
return mkdirSync(path)
return mkdirSync(path);
} catch (err) {
if (err.code !== 'EEXIST') throw err
if (err.code !== "EEXIST") throw err;
}
}
@@ -17,7 +19,7 @@ function writeFile(path, content) {
} catch (err) {
if (err) throw err;
}
console.log(`${path} updated.`);
console.log(`${path} updated.`);
}
function slugify(str) {
@@ -41,10 +43,15 @@ function cleanWebsite(str) {
}
function metaDescription({ name, meta, description }) {
if (meta && (meta.length > 155 || meta.length < 145 && meta.length !== 0)) {
console.log(`warning: meta tag for ${name} is invalid: 145/${meta.length}/155`)
if (meta && (meta.length > 155 || (meta.length < 145 && meta.length !== 0))) {
console.log(
`warning: meta tag for ${name} is invalid: 145/${meta.length}/155`
);
}
return meta || description.length > 155 ? description.slice(0, 153) + "..." : description || "A guide to and map of every independent bookstore in New York City. We have a complete list of community bookstores in NYC with locations and descriptions."
return meta || description.length > 155
? description.slice(0, 153) + "..."
: description ||
"A guide to and map of every independent bookstore in New York City. We have a complete list of community bookstores in NYC with locations and descriptions.";
}
function GetRecentChanges() {
@@ -176,15 +183,17 @@ readFile("./index.tmpl.html", function (err, data) {
rmSync("./build", { recursive: true, force: true });
mkDir("./build")
writeFile("./build/index.html", $.html())
mkDir("./build");
writeFile("./build/index.html", $.html());
cpSync("./site.css", "./build/site.css");
cpSync("./robots.txt", "./build/robots.txt");
cpSync("./img", "./build/img", {recursive: true});
cpSync("./img", "./build/img", { recursive: true });
cpSync("./stores.json", "./build/stores.json");
let pages = [{ url: `/` }];
stores.forEach((store) => {
$("#selected").html(SelectedStoreTemplate(store));
$("#info").addClass("hidden");
@@ -192,7 +201,18 @@ readFile("./index.tmpl.html", function (err, data) {
$("title").html(title);
$("meta[name='title']").attr("content", title);
$("meta[name='description']").attr("content", metaDescription(store));
$("link[rel='canonical']").attr(
"href",
`https://www.nycbookstores.org/${slugify(store.name)}/`
);
mkDir(`./build/${slugify(store.name)}`);
writeFile(`./build/${slugify(store.name)}/index.html`, $.html());
pages.push({ url: `/${slugify(store.name)}/` });
});
simpleSitemapAndIndex({
hostname: "https://www.nycbookstores.org/",
destinationDir: `./build/`,
sourceData: pages,
gzip: false,
});
});

249
package-lock.json generated
View File

@@ -9,33 +9,55 @@
"version": "1.0.0",
"license": "BSD-3-Clause",
"dependencies": {
"cheerio": "^1.0.0-rc.12"
"cheerio": "^1.0.0",
"sitemap": "^8.0.0"
}
},
"node_modules/@types/node": {
"version": "17.0.45",
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz",
"integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==",
"license": "MIT"
},
"node_modules/@types/sax": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz",
"integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==",
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/arg": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
"integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
"license": "MIT"
},
"node_modules/boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
},
"node_modules/cheerio": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0.tgz",
"integrity": "sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==",
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.1.2.tgz",
"integrity": "sha512-IkxPpb5rS/d1IiLbHMgfPuS0FgiWTtFIm/Nj+2woXDLTZ7fOT2eqzgYbdMlLweqlHbsZjxEChoVK+7iph7jyQg==",
"dependencies": {
"cheerio-select": "^2.1.0",
"dom-serializer": "^2.0.0",
"domhandler": "^5.0.3",
"domutils": "^3.1.0",
"encoding-sniffer": "^0.2.0",
"htmlparser2": "^9.1.0",
"parse5": "^7.1.2",
"parse5-htmlparser2-tree-adapter": "^7.0.0",
"domutils": "^3.2.2",
"encoding-sniffer": "^0.2.1",
"htmlparser2": "^10.0.0",
"parse5": "^7.3.0",
"parse5-htmlparser2-tree-adapter": "^7.1.0",
"parse5-parser-stream": "^7.1.2",
"undici": "^6.19.5",
"undici": "^7.12.0",
"whatwg-mimetype": "^4.0.0"
},
"engines": {
"node": ">=18.17"
"node": ">=20.18.1"
},
"funding": {
"url": "https://github.com/cheeriojs/cheerio?sponsor=1"
@@ -122,9 +144,9 @@
}
},
"node_modules/domutils": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
"integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
"integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
"dependencies": {
"dom-serializer": "^2.0.0",
"domelementtype": "^2.3.0",
@@ -135,9 +157,9 @@
}
},
"node_modules/encoding-sniffer": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz",
"integrity": "sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==",
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz",
"integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==",
"dependencies": {
"iconv-lite": "^0.6.3",
"whatwg-encoding": "^3.1.1"
@@ -158,9 +180,9 @@
}
},
"node_modules/htmlparser2": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz",
"integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==",
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.0.0.tgz",
"integrity": "sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==",
"funding": [
"https://github.com/fb55/htmlparser2?sponsor=1",
{
@@ -171,8 +193,19 @@
"dependencies": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3",
"domutils": "^3.1.0",
"entities": "^4.5.0"
"domutils": "^3.2.1",
"entities": "^6.0.0"
}
},
"node_modules/htmlparser2/node_modules/entities": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
"integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/iconv-lite": {
@@ -198,22 +231,22 @@
}
},
"node_modules/parse5": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
"integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
"integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==",
"dependencies": {
"entities": "^4.4.0"
"entities": "^6.0.0"
},
"funding": {
"url": "https://github.com/inikulin/parse5?sponsor=1"
}
},
"node_modules/parse5-htmlparser2-tree-adapter": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz",
"integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==",
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz",
"integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==",
"dependencies": {
"domhandler": "^5.0.2",
"domhandler": "^5.0.3",
"parse5": "^7.0.0"
},
"funding": {
@@ -231,17 +264,53 @@
"url": "https://github.com/inikulin/parse5?sponsor=1"
}
},
"node_modules/parse5/node_modules/entities": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
"integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"node_modules/undici": {
"version": "6.19.7",
"resolved": "https://registry.npmjs.org/undici/-/undici-6.19.7.tgz",
"integrity": "sha512-HR3W/bMGPSr90i8AAp2C4DM3wChFdJPLrWYpIS++LxS8K+W535qftjt+4MyjNYHeWabMj1nvtmLIi7l++iq91A==",
"node_modules/sax": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
"integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
"license": "ISC"
},
"node_modules/sitemap": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/sitemap/-/sitemap-8.0.0.tgz",
"integrity": "sha512-+AbdxhM9kJsHtruUF39bwS/B0Fytw6Fr1o4ZAIAEqA6cke2xcoO2GleBw9Zw7nRzILVEgz7zBM5GiTJjie1G9A==",
"license": "MIT",
"dependencies": {
"@types/node": "^17.0.5",
"@types/sax": "^1.2.1",
"arg": "^5.0.0",
"sax": "^1.2.4"
},
"bin": {
"sitemap": "dist/cli.js"
},
"engines": {
"node": ">=18.17"
"node": ">=14.0.0",
"npm": ">=6.0.0"
}
},
"node_modules/undici": {
"version": "7.15.0",
"resolved": "https://registry.npmjs.org/undici/-/undici-7.15.0.tgz",
"integrity": "sha512-7oZJCPvvMvTd0OlqWsIxTuItTpJBpU1tcbVl24FMn3xt3+VSunwUasmfPJRE57oNO1KsZ4PgA1xTdAX4hq8NyQ==",
"engines": {
"node": ">=20.18.1"
}
},
"node_modules/whatwg-encoding": {
@@ -265,26 +334,44 @@
}
},
"dependencies": {
"@types/node": {
"version": "17.0.45",
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz",
"integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw=="
},
"@types/sax": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz",
"integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==",
"requires": {
"@types/node": "*"
}
},
"arg": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
"integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
},
"boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
},
"cheerio": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0.tgz",
"integrity": "sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==",
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.1.2.tgz",
"integrity": "sha512-IkxPpb5rS/d1IiLbHMgfPuS0FgiWTtFIm/Nj+2woXDLTZ7fOT2eqzgYbdMlLweqlHbsZjxEChoVK+7iph7jyQg==",
"requires": {
"cheerio-select": "^2.1.0",
"dom-serializer": "^2.0.0",
"domhandler": "^5.0.3",
"domutils": "^3.1.0",
"encoding-sniffer": "^0.2.0",
"htmlparser2": "^9.1.0",
"parse5": "^7.1.2",
"parse5-htmlparser2-tree-adapter": "^7.0.0",
"domutils": "^3.2.2",
"encoding-sniffer": "^0.2.1",
"htmlparser2": "^10.0.0",
"parse5": "^7.3.0",
"parse5-htmlparser2-tree-adapter": "^7.1.0",
"parse5-parser-stream": "^7.1.2",
"undici": "^6.19.5",
"undici": "^7.12.0",
"whatwg-mimetype": "^4.0.0"
}
},
@@ -342,9 +429,9 @@
}
},
"domutils": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz",
"integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==",
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
"integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
"requires": {
"dom-serializer": "^2.0.0",
"domelementtype": "^2.3.0",
@@ -352,9 +439,9 @@
}
},
"encoding-sniffer": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.0.tgz",
"integrity": "sha512-ju7Wq1kg04I3HtiYIOrUrdfdDvkyO9s5XM8QAj/bN61Yo/Vb4vgJxy5vi4Yxk01gWHbrofpPtpxM8bKger9jhg==",
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz",
"integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==",
"requires": {
"iconv-lite": "^0.6.3",
"whatwg-encoding": "^3.1.1"
@@ -366,14 +453,21 @@
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="
},
"htmlparser2": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz",
"integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==",
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.0.0.tgz",
"integrity": "sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==",
"requires": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3",
"domutils": "^3.1.0",
"entities": "^4.5.0"
"domutils": "^3.2.1",
"entities": "^6.0.0"
},
"dependencies": {
"entities": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
"integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="
}
}
},
"iconv-lite": {
@@ -393,19 +487,26 @@
}
},
"parse5": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
"integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
"integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==",
"requires": {
"entities": "^4.4.0"
"entities": "^6.0.0"
},
"dependencies": {
"entities": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
"integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="
}
}
},
"parse5-htmlparser2-tree-adapter": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz",
"integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==",
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz",
"integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==",
"requires": {
"domhandler": "^5.0.2",
"domhandler": "^5.0.3",
"parse5": "^7.0.0"
}
},
@@ -422,10 +523,26 @@
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"sax": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
"integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="
},
"sitemap": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/sitemap/-/sitemap-8.0.0.tgz",
"integrity": "sha512-+AbdxhM9kJsHtruUF39bwS/B0Fytw6Fr1o4ZAIAEqA6cke2xcoO2GleBw9Zw7nRzILVEgz7zBM5GiTJjie1G9A==",
"requires": {
"@types/node": "^17.0.5",
"@types/sax": "^1.2.1",
"arg": "^5.0.0",
"sax": "^1.2.4"
}
},
"undici": {
"version": "6.19.7",
"resolved": "https://registry.npmjs.org/undici/-/undici-6.19.7.tgz",
"integrity": "sha512-HR3W/bMGPSr90i8AAp2C4DM3wChFdJPLrWYpIS++LxS8K+W535qftjt+4MyjNYHeWabMj1nvtmLIi7l++iq91A=="
"version": "7.15.0",
"resolved": "https://registry.npmjs.org/undici/-/undici-7.15.0.tgz",
"integrity": "sha512-7oZJCPvvMvTd0OlqWsIxTuItTpJBpU1tcbVl24FMn3xt3+VSunwUasmfPJRE57oNO1KsZ4PgA1xTdAX4hq8NyQ=="
},
"whatwg-encoding": {
"version": "3.1.1",

View File

@@ -14,7 +14,8 @@
},
"homepage": "https://www.nycbookstores.org/",
"dependencies": {
"cheerio": "^1.0.0-rc.12"
"cheerio": "^1.0.0",
"sitemap": "^8.0.0"
},
"type": "module"
}

View File

@@ -0,0 +1 @@
Sitemap: https://nycbookstores.org/sitemap-index.xml

View File

@@ -329,21 +329,6 @@
"cafe": "No",
"meta": "Three Lives & Company, in the West Village, Manhattan, is a gorgeous neighborhood bookstore with knowledgable staff and a selection of literary fiction."
},
{
"name": "Shakespeare & Company",
"address": "939 Lexington Ave",
"city": "New York",
"state": "NY",
"postcode": "10065",
"description": "Sharing a name with the famous Parisian bookshop but no other official ties, this store has a general-interest selection of books on its main level and, downstairs, textbooks for the nearby colleges.",
"lat": "40.768188",
"long": "-73.963531",
"country": "USA",
"website": "https://shop.shakeandco.com/",
"events": "Yes",
"cafe": "Yes",
"meta": ""
},
{
"name": "Book Culture",
"address": "536 W 112th St",
@@ -1185,12 +1170,12 @@
"meta": ""
},
{
"name": "Shakespeare & Company (Upper West Side)",
"name": "Strand Bookstore (Upper West Side)",
"address": "2020 Broadway",
"city": "New York",
"state": "NY",
"postcode": "10023",
"description": "",
"description": "Formerly Shakespeare and Company Lincoln Center.",
"lat": "40.776484",
"long": "-73.981811",
"country": "USA",
@@ -1709,21 +1694,6 @@
"cafe": "Yes",
"meta": ""
},
{
"name": "Shakespeare & Company (Manhattan Valley/Columbia University)",
"address": "2736 Broadway",
"city": "New York",
"state": "NY",
"postcode": "10025",
"description": "",
"lat": "40.800259699774",
"long": "-73.96768731230581",
"country": "USA",
"website": "https://shop.shakeandco.com/",
"events": "Yes",
"cafe": "No",
"meta": ""
},
{
"name": "Liz's Book Bar",
"address": "315 Smith St",
@@ -1798,5 +1768,65 @@
"events": "Yes",
"cafe": "Yes",
"meta": ""
},
{
"name": "The Fountain Bookshop",
"address": "803 W 187th St",
"city": "New York",
"state": "NY",
"postcode": "10033",
"description": "",
"lat": "40.85536319660771",
"long": "-73.9369908112493",
"country": "USA",
"website": "https://fountainbookshop.com/",
"events": "Yes",
"cafe": "Yes",
"meta": ""
},
{
"name": "Twisted Spine Books",
"address": "306 Grand St",
"city": "Brooklyn",
"state": "NY",
"postcode": "11211",
"description": "",
"lat": "40.71281455385764",
"long": "-73.95724940889518",
"country": "USA",
"website": "https://www.twistedspinebooks.com/",
"events": "Yes",
"cafe": "No",
"meta": ""
},
{
"name": "Gladys Books & Wine",
"address": "306 Malcolm X Blvd",
"city": "Brooklyn",
"state": "NY",
"postcode": "11233",
"description": "",
"lat": "40.682375148825216",
"long": "-73.92910519253844",
"country": "USA",
"website": "https://www.gladysbooksandwine.com/",
"events": "Yes",
"cafe": "Yes",
"meta": ""
},
{
"name": "White Rabbit's Books",
"address": "200 West 86th St",
"city": "New York",
"state": "NY",
"postcode": "10024",
"description": "",
"lat": "40.78773297148539",
"long": "-73.9754510091096",
"country": "USA",
"website": "https://whiterabbitsbooks.com/",
"events": "Yes",
"cafe": "No",
"meta": ""
}
]