23 Commits

Author SHA1 Message Date
b5ceed8279 Update node Docker tag to v25
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-10-16 19:02:21 +00:00
2d6ba8a5a7 Rest in peace, Bluestockings
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-10-03 02:09:07 +00:00
cca8af0b93 Tweak meta tag
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-09-13 02:24:47 +00:00
a8d8cb232d add description and meta for Twisted Spine (thx Lisa)
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2025-09-13 02:15:14 +00:00
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 281 additions and 127 deletions

View File

@@ -1,9 +1,9 @@
FROM node:22 AS builder
FROM node:25 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")
mkDir("./build");
writeFile("./build/index.html", $.html())
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

@@ -284,21 +284,6 @@
"cafe": "No",
"meta": "Strand Bookstore, near Union Square in Manhattan, is the best-known bookseller in the city, stocking new, used, and rare books on \"18 miles\" of shelves."
},
{
"name": "Bluestockings Cooperative",
"address": "116 Suffolk Street",
"city": "New York",
"state": "NY",
"postcode": "10002",
"description": "Taking its name from a disparaging term for female intellectuals in the Victorian era, this radical bookstore, café, and activist space has a selection of anarchist, socialist, Marxist, and other revolutionary texts available, as well as queer lit and some general interest fiction. Shirts, 'zines, and stickers also available. $10 credit card minimum.",
"lat": "40.718920281950105",
"long": "-73.98591840219963",
"country": "USA",
"website": "https://bluestockings.com/",
"events": "Yes",
"cafe": "Yes",
"meta": "Bluestockings Cooperative Bookstore, in the Bowery, Manhattan, is a community-focused and collectively-run activist center and feminist bookstore and cafe."
},
{
"name": "Kinokunya",
"address": "1073 Avenue of the Americas",
@@ -329,21 +314,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",
@@ -515,7 +485,7 @@
"city": "New York",
"state": "NY",
"postcode": "10037",
"description": "If bluestockings is the friendly face of a feminist co-operative, its revolutionary counterpart in New York City is the appropriately-named Revolution Books, a bastion of communism in the Big Apple. It specializes in revolutionary political texts, of course, but also has a broad selection of those same texts in Spanish. Special promotional space given to books by Bob Avakian, chairman of the Revolutionary Communist Party USA (not to be confused with the Communist Party USA).",
"description": "If the revolution ever arrives in New York City, perhaps its nexus will be the appropriately-named Revolution Books, a bastion of communism in the Big Apple. It specializes in revolutionary political texts, of course, but also has a broad selection of those same texts in Spanish. Special promotional space given to books by Bob Avakian, chairman of the Revolutionary Communist Party USA (not to be confused with the Communist Party USA).",
"lat": "40.8121889",
"long": "-73.9448338",
"country": "USA",
@@ -1185,12 +1155,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 +1679,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 +1753,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": "Twisted Spine focused on horror fiction, meticulously organized into sub-genre and sub-sub-genre, including non-fiction and a children's section. Their staff are knowledgable about the genre, and the decor correctly vibes with the horror emphasis. Shop includes a backyard area, indoor seating, and free wifi.",
"lat": "40.71281455385764",
"long": "-73.95724940889518",
"country": "USA",
"website": "https://www.twistedspinebooks.com/",
"events": "Yes",
"cafe": "Yes",
"meta": "Twisted Spine, in Williamsburg, Brooklyn, is dedicated to horror fiction and non-fiction. Store includes a cafe, backyard area, and indoor seating."
},
{
"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": ""
}
]